Sucker (присоска) — PHP компонент для теста приватных методов и свойств
В рамках хобби пишу свои собственные компоненты.
Но есть проблема — отсутствие аудитории.
Чтобы полноценно тестировать компоненты на работоспособность, решил через Хабр дать популярность некоторым своим компонентам.
На днях дописал компонент который универсально может взаимодействовать с приватными свойствами и методами классов и объектов. Цель такого доступа — тестировать работоспособность скрытого когда.
alpa/tools_sucker — https://packagist.org/packages/alpa/tools_sucker
https://github.com/alexeyp0708/php_tools_sucker
Возможно вы зададитесь вопросом — тема стара как мир, зачем еще один схожий компонент?
Например есть легковесная в несколько строк spatie/invade — https://packagist.org/packages/spatie/invade
Да и «на коленке» можно написать свою реализацию.
НО…, согласитесь, всегда охота иметь под рукой легко понятный, прозрачный и универсальный инструмент.
Но хз. Мне нравится писать свои тяжеловесные компоненты.
Ознакомившись, вы поймете насколько прост и эффективен данный компонент.
Я дам обзор кратко. Если проявится интерес то обязательно оцените на гитхабе.
Установка и классы взаимодействия
Установка
composer require alpa/tools_sucker:1.0.*
Использование
Есть три рабочих класса взаимодействия с приватными членами объекта/класса. Но для обзора я опишу два класса:
\Alpa\Tools\Sucker\Sucker — использует явные геттеры и сеттеры для взаимодействия с объектом или классом.
Alpa\Tools\Sucker\Proxy — прокси объект, который использует магию для доступа к объектам и свойствам объекта или класса.
Для примера создадим два подопытных класса
Sucker класс
Доступ к приватным членам объекта
get('private_prop');// bay
echo "\n";
// получаем доступ к приватному совйтсву родительского класса A
echo $sucker(A::class)->get('private_prop');// hello
echo "\n";
echo $sucker->get('private_prop');// bay
echo "\n";
//get by reference
$var = & $sucker(A::class)->get('private_prop');// $var = & A::$private_prop ==='hello'
Доступ к приватным статическим членам класса
get('static_private_prop');// bay
echo "\n";
echo $sucker(A::class)->get('static_private_prop');// hello
echo "\n";
// Warn : The Scope is automatically reset after calling methods that are responsible for accessing members of the observable object
echo $sucker->get('static_private_prop');// bay
echo "\n";
//get by reference
$var = & $sucker(A::class)->get('static_private_prop');// $var = & A::$static_private_prop ==='hello'
API Sгcker класса
get( $prop ); & $sucker( SCOPE::class )->get( $prop );
// установить значение для свойства обькта/класса
$sucker->set( $prop, $value ); $sucker(SCOPE::class)->set( $prop, $value );
// установить значение для свойства обькта/класса по ссылке
$sucker->setRef( $prop, & $value ); $socker(SCOPE::class)->setRef( $prop, & $value );
// проверить наличие свойства обькта/класса
$sucker->isset( $prop ); $sucker(SCOPE::class)->isset( $prop );
// удалить свойство из обьекта. для статического свойства класса будет вызвана стандартная ошибка.
$sucker->unset( $prop ); $sucker(SCOPE::class)->unset( $prop );
// перебрать свойства объекта/класса.
/* in each closure => self::class===SCOPE::class and opening $this */
$sucker->each(function ( $key, & $value ){return true;/* break*/}); $sucker( SCOPE::class )->each( function ($key, & $value){return true;/*break*/} );
// вызвать метод объекта/класса.
& $sucker->call( $method, ...$args ); & $sucker( SCOPE::class )->call( $prop ,...$args );
// вызвать метод объекта/класса с возможностьбю передачи аргументов по ссылке.
& $sucker->apply( $method, [& $arg,...] ); & $sucker( SCOPE::class )->apply( $method, [& $arg,...] );
// Песочница для обработки обьекта по своему усмотрению
/* in sandbox closure => self::class===SCOPE::class and opening $this */
& $sucker->sandbox( function & (& $arg){},[ & $arg,...] ); & $sucker( SCOPE::class )->sandbox( function & (& $arg){},[ & $arg,...] );
Proxy класс
Объект прокси класса позволяет работать, так как будто вы имеете контакт с самим объектом.
private_prop;// bay
echo $proxy(A::class)->private_prop;// hello
echo $proxy->private_prop;// bay
// доступ к статическим свойствам класса.
$proxy=new Proxy(B::class);
echo $proxy->static_private_prop;// bay
echo $proxy(A::class)->static_private_prop;// hello
echo $proxy->static_private_prop;// bay
// get by reference
$var = & $proxy->static_private_prop;
API Proxy класса
prop; & $proxy(SCOPE::class)->prop;
// установить значение для свойства обькта/класса
$proxy->prop=$vslue; $proxy(SCOPE::class)->prop=$value;
// проверить наличие свойства обькта/класса
isset($proxy->prop); isset($proxy(SCOPE::class)->prop);
// удалить свойство из обьекта. для статического свойства класса будет вызвана стандартная ошибка.
unset($proxy->prop); unset($proxy(SCOPE::class)->prop);
// перебрать свойства объекта/класса.
foreach ($proxy as $key=>$value){
}
foreach ($proxy(SCOPE::class) as $key=>$value){
}
// вызвать метод объекта/класса.
& $proxy->method(...$args); & $proxy(SCOPE::class)->method(...$args);
/* Песочница для обработки обьекта по своему усмотрению.
Аргументы можно передавать по ссылке, а также результат получать по ссылке*.
/* in sandbox closure => self::class===SCOPE::class and opening $this */
& $proxy(function & (...$args){},[& $arg,...]); & $proxy(SCOPE::class)(function & (...$args){},[ & $arg,...]);
Удобно? Практично? — решать вам.
Сильно не критикуйте. Писать код это вам не «хухры мухры».
Всем спасибо. Ставьте звездочку на гитхабе.