PHP ReflectionClass hasMethod и __call () - PullRequest
       30

PHP ReflectionClass hasMethod и __call ()

3 голосов
/ 09 апреля 2011

Я создаю динамический класс, который реагирует на магический метод __call(). Проблема в том, что, поскольку я строю это поверх уже существующего фреймворка (Kohana), он проверяет, существует ли метод класса с использованием ReflectionClass::hasMethod, и, похоже, не вызывает магический метод __call() проверяя его существование. Что я мог сделать в этом случае? Похоже, если вы добавите метод динамически (например, $this->{$name} = function(){}), он все равно не сможет "увидеть" его

Ответы [ 2 ]

2 голосов
/ 09 апреля 2011

Без подробностей я не уверен, что этого будет достаточно, однако вы можете создать прокси-класс для выполнения промежуточных функций:

   class MyProxy {

    protected $_object  = null;
    protected $_methods = array();

    public function __construct($object) {
        if (!is_object($object)) {
            throw new InvalidArgumentException('$object must be an object');
        }
        $this->_object = $object;
    }

    public function __call($name, $arguments) {
        return $this->callMethod($name, $arguments);
    }

    public function setMethod($name, Closure $method) {
        $this->_methods[(string) $key] = $method;
    }

    public function callMethod($name, array $arguments) {
        if (isset($this->_methods[$name])) {
            return call_user_func_array($this->_methods[$name], $arguments);
        }
        return call_user_func_array(array($this->_object, $name), $arguments);
    }

}

Вызывая $proxy->setMethod('foo', function () { });, вы можете динамически «прикреплять» методы к объекту. Когда вы вызываете $proxy->foo(), он сначала проверяет динамически присоединенные методы; если он найдет его, он назовет его. В противном случае он просто делегирует внутренний объект.

Теперь проблема этого подхода в том, что прикрепленные методы не привязаны к прокси. Другими словами, $this не существует в области действия присоединенного метода.

Это можно исправить с помощью функций из PHP 5.4 +.

public function setMethod($name, Closure $method) {
    $this->_methods[(string) $name] = Closure::bind($method, $this);
}

Мы уточнили setMethod до , чтобы повторно связать пройденное закрытие с прокси. Теперь в области действия присоединенного метода $this будет указывать на прокси-объект.

Мы могли бы привязать его к вложенному объекту, но тогда присоединенные методы не могли общаться с прокси ( или другими присоединенными методами ). Для полноты вы захотите добавить магию __get и __set, чтобы переадресовывать вызовы доступа к свойству / мутировать во внутренний объект ( или обрабатывать их в прокси, независимо от того, )

Кроме того, внутренний объект не имеет ни малейшего представления о прокси, поэтому его методы ( из определения класса ) в любом случае не будут знать о какой-либо из этих динамических магии.

1 голос
/ 09 апреля 2011

Похоже, что если вы добавляете метод динамически (например, $this->{$name} = function(){}), он все равно не может его "увидеть"

Верно, когда вы создаете новое свойство , а не метод. На момент написания PHP не поддерживал вызов анонимных функций в свойствах без прохождения через __call, что не удобно для отражения. Свойства с анонимными функциями как работают правильнов PHP 5.4.

Единственный способ добавить метод к классу таким образом, чтобы Reflection использовал его, - это очень экспериментальное расширение runkit .

...