Привет, Habr! Сегодня хочу рассказать про свой костыль, который помог мне не погружаться в дебри PHP Reflection. Ведь все пишут костыли, просто кто-то пишет большие, а кто-то поменьше.
Я активно использую Laravel в своих проектах. Для тех, кто не знаком с этим framework'ом — не отчаивайтесь, потому что я объясню непонятные моменты.
В этот раз я писал некоторое расширение правил валидации:
Validator::extend('someRule', function ($attribute, $value, $parameters, $validator) {
// some code...
return $result; // boolean
}, ':attribute is invalid');
И мне потребовалось получить список всех правил, передаваемых валидатору. Как оказалось, эта простая на первый взгляд задача заняла у меня немного больше времени, чем я планировал. Свойство было приватным. И никаких getter'ов для него в реализации класса не было. Изменять класс я конечно же не стал, ибо после composer update эта правка тут же слетит.
Следует сказать, что раньше я никогда не использовал Reflection, но слышал, для чего оно используется. Так вот, я начал читать документацию. Естественно, код из примера с первого раза не завелся и нужно было искать еще. И тут я подумал, что решение должно быть проще.
И я нашел таки простой и элегантный костыль. Все-таки так лучше не делать. Приватные свойства на то и приватные, чтобы туда не лазили. Но обстоятельства требуют, так что...
Validator::extend('someRule', function ($attribute, $value, $parameters, $validator) {
// Это функция-ниндзя. Она врывается в валидатор и крадет приватное свойство.
// Это очень коварно и подло, но у меня нет другого выбора (есть, но там писать больше)
$ninja = function() {
// именно в этом свойстве хранится массив с нужными мне данными
return $this->initialRules;
};
$initialRules = $ninja->call($validator); // параметр $newThis
// some code
return $result;
}, ':attribute is invalid');
Если кто-то еще не понял, объясню: я создал анонимную функцию, которая возвращает некоторое свойство. А потом просто подменил контекст на контекст валидатора (laravel передает экземпляр этого класса). Тоесть, замыкание теперь имеет доступ к этому объекту изнутри и может получить доступ к любому приватному свойству и методу.
Работает вся это красота, начиная с PHP 5.4
Это собственно все, что я хотел рассказать. Может до меня это уже изобрели, но в мою голову это идея пришла сама, поэтому я решил ею поделиться. Вдруг, это решение упростит кому-то жизнь.
Спасибо за внимание.