В рамках хобби пишу свои собственные компоненты.
Но есть проблема - отсутствие аудитории.
Чтобы полноценно тестировать компоненты на работоспособность, решил через Хабр дать популярность некоторым своим компонентам.
На днях дописал компонент который универсально может взаимодействовать с приватными свойствами и методами классов и объектов. Цель такого доступа - тестировать работоспособность скрытого кода.
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 - прокси объект, который использует магию для доступа к объектам и свойствам объекта или класса.
Для примера создадим два подопытных класса
<?php class A{ private $private_prop='hello'; private static $static_private_prop='hello'; private function private_method($arg) { return $arg; } private function & private_methodByReference(&$arg=null) { return $arg; } } class B extends A{ private $private_prop='bay'; private static $static_private_prop='bay'; private function private_method($arg) { return strtoupper($arg); } }
Sucker класс
Доступ к приватным членам объекта
<?php use A; use B; use Alpa\Tools\Sucker\Sucker; // доступ к приватным членам обьекта. $sucker=new Sucker(new B); // получаем доступ к приватному совйтсву класса B echo $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'
Доступ к приватным статическим членам класса
<?php use A; use B; use Alpa\Tools\Sucker\Sucker; // доступ к приватным статическим членам класса. $sucker=new Sucker(B::class); echo $sucker->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 класса
<?php use Alpa\Tools\Sucker\Sucker; $sucker = new Socker($object); // for members object // or $sucker=new Sucker(Target::class); // for static members class // при смене области видимости, обьект один и тот же (а не создается новый) $sucker===$sucker(A::class); // сброc область видимости $sucker(null); /* Внимание: область видимости сохраняется до первого вызова метода API и после сбрасывается на область видимости по умолчанию (класс обьекта).*/ /* & - указывает что аргументы нужно передавать по ссылке (в аргументах указан только для наглядности), или можно получать результат по ссылке. */ // запросить значение свойства обькта/класса (можно по сыслке) & $sucker->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 класс
Объект прокси класса позволяет работать, так как будто вы имеете контакт с самим объектом.
<?php use A; use B; use Alpa\Tools\Sucker\Proxy; $proxy=new Proxy(new B); echo $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 класса
<?php use Alpa\Tools\Sucker\Proxy; $proxy = new Proxy($object); // for members object // or $proxy=new Sucker(Target::class); // for static members class // при смене области видимости, обьект один и тот же (а не создается новый) $proxy===$proxy(A::class); // сброc область видимости $proxy(null); /* Внимание: область видимости сохраняется до первого вызова метода 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,...]);
Удобно? Практично? - решать вам.
Сильно не критикуйте. Писать код это вам не "хухры мухры".
Всем спасибо. Ставьте звездочку на гитхабе.
