2013-10-30 php-apply
Вот пишут люди про PHP ерунду всякую — фрактал плохого дизайна… сравнение нетранзитивное… ещё что-то там… Так вот, это всё фигня и вообще не расстраивает ни разу (разве что соглашусь, что синтаксис и реализация неймспейсов дебильны).
А вот что меня реально всегда расстраивало — так это то, что в PHP классы после загрузки нельзя модифицировать извне. Ну то есть можно — есть runkit, и говорят, что он в последнее время даже работает (когда я его пробовал 2-3 года назад — не работал, крашился). Но он довольно нетривиален, делает всякую магию — копирует байткод функции, меняет переходы… Не факт, что это быстро, и также не факт, что не отвалится в будущем.
Особенно «модификация класса извне» становится актуальна с появлением trait’ов (примесей), которые авторы реализовали, но реализовали как-то косо и по моему ощущению они там ни к селу, ни к городу. Вроде хочется, чтобы trait был таким себе плагинчиком, который можно подоткнуть в класс в любой момент, ан нет — его надо use внутри самого определения класса, да ещё применить довольно странный синтаксис разрешения конфликтов имён:class X { use Trait1, Trait2 { Trait1::a insteadof Trait2; } }
Если взглянуть немного шире, становится ясно, что зачастую сам класс-то менять, в общем, и не обязательно, достаточно сделать ему apply(), как в js — то есть вызвать внешнюю функцию в контексте произвольного объекта. Но и этого в php сделать нельзя, потому что $this — это не просто первый аргумент функции, как в перле или питоне, а некое поле внутренних структур движка, которое просто так не поменяешь. Ну, и ещё в отличие от js есть protected/private методы.
Так вот — сегодня меня вштырило и я этот apply родил в виде тривиального экстенжна с одной функцией — apply_user_func(object $object, callable $callback, array $args).
С ним можно делать вот так:
class A { var $b = "abc\n"; private function f_a() { print "Опа!\n"; } } function f() { print $this->b; // нам будет доступно поле класса A $this->f_a(); // и его private метод тоже будет доступен } $a = new A(); apply_user_func($a, 'f', array());
Экстенжн реально тривиальный, всего сотня с лишним строчек, из которых НЕ-копипасты — на самом деле вообще строчек 8. Ну, тест ещё 76 строчек, ок.
В общем, можно юзать :) под 5.4 и 5.5 работает. По скорости работает чууть-чуть помедленнее, чем call_user_func_array с аналогичной семантикой, и где-то на 80% медленнее, чем обычный вызов функции.
- Скачать .tar.gz можно тут: http://svn.yourcmc.ru/viewvc.py/vitalif/trunk/php-apply/?view=tar
- Просмотр кода онлайн: http://svn.yourcmc.ru/viewvc.py/vitalif/trunk/php-apply/
[ Хронологический вид ]Комментарии
Войдите, чтобы комментировать.