Мне интересно, есть ли способ прикрепить новый метод к классу во время выполнения, в php. Я имею в виду не на уровне экземпляра, а непосредственно в классе, так что все вновь созданные экземпляры имеют этот новый метод. Можно ли это сделать с отражением?
благодаря
Да, ты можешь.
Ниже приведен способ создания метода во время выполнения в php 5.4.x.
Анонимная функция представлена классом Closure, начиная с 5.3.x. Из 5.4.x он добавляет статический метод Closure :: bind для привязки анонимной функции к определенному объекту или классу.
Пример:
class Foo { private $methods = array(); public function addBar() { $barFunc = function () { var_dump($this->methods); }; $this->methods['bar'] = \Closure::bind($barFunc, $this, get_class()); } function __call($method, $args) { if(is_callable($this->methods[$method])) { return call_user_func_array($this->methods[$method], $args); } } } $foo = new Foo; $foo->addBar(); $foo->bar();
Некоторые играли со всей штукой. Кажется, что единственное, что вы можете потенциально сделать с ReflectionClass
– это заменить существующий метод. Но даже это было бы косвенно.
На самом деле я не знаю языка на основе классов, где существуют динамические классы (тогда, опять же, мои знания весьма ограничены). Я видел это только в языках, основанных на прототипах (javascript, ruby, smalltalk). Вместо этого в PHP 5.4 вы можете использовать Closure
и добавлять новые методы к существующему объекту .
Вот класс, который позволит вам выполнить такое извращение для любого объекта:
class Container { protected $target; protected $className; protected $methods = []; public function __construct( $target ) { $this->target = $target; } public function attach( $name, $method ) { if ( !$this->className ) { $this->className = get_class( $this->target ); } $binded = Closure::bind( $method, $this->target, $this->className ); $this->methods[$name] = $binded; } public function __call( $name, $arguments ) { if ( array_key_exists( $name, $this->methods ) ) { return call_user_func_array( $this->methods[$name] , $arguments ); } if ( method_exists( $this->target, $name ) ) { return call_user_func_array( array( $this->target, $name ), $arguments ); } } }
Чтобы использовать это, вы должны предоставить конструктору существующий объект. Вот небольшой пример использования:
class Foo { private $bar = 'payload'; }; $foobar = new Foo; // you initial object $instance = new Container( $foobar ); $func = function ( $param ) { return 'Get ' . $this->bar . ' and ' . $param; }; $instance->attach('test', $func); // setting up the whole thing echo $instance->test('lorem ipsum'); // 'Get payload and lorem ipsum'
Не совсем то, что вы хотите, но AFAIK это как можно ближе.
Вы взглянули на create_function () в документах? Вы также можете достичь желаемого результата при перегрузке .
Это возможно с помощью runkit_method_add () расширения runkit . Будьте осторожны, используя это в производстве.
Пример:
<?php class Example {} $e = new Example(); runkit_method_add( 'Example', 'add', '$num1, $num2', 'return $num1 + $num2;', RUNKIT_ACC_PUBLIC ); echo $e->add(12, 4);