【问题标题】:PHP ReflectionClass hasMethod and __call()PHP ReflectionClass hasMethod 和 __call()
【发布时间】:2011-08-02 05:00:15
【问题描述】:

我正在创建一个响应魔术__call() 方法的动态类。问题是,由于我是在已经存在的框架(Kohana)之上构建它,它使用ReflectionClass::hasMethod 检查类的方法是否存在,并且它似乎没有触发__call() 魔术方法检查它的存在。在这种情况下我能做什么?好像如果你动态添加方法(比如$this->{$name} = function(){})它仍然不能“看到”它

【问题讨论】:

    标签: php reflection dynamic call magic-methods


    【解决方案1】:

    如果没有更多细节,我不确定这是否足够,但是您可以创建代理类来执行中间功能:

       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 细化为 rebind the passed closure 到代理。现在,在附加方法的范围内,$this 将指向代理对象。

    我们可以将它重新绑定到封闭的对象,但是附加的方法无法与代理(或其他附加的方法)对话。为了完整起见,您需要添加 __get__set 魔术,以将属性访问/变异调用转发到内部对象(或在代理中处理它们,无论如何

    此外,内部对象对代理一无所知,因此它的方法(来自类定义)无论如何也不知道任何这种动态魔法。

    【讨论】:

      【解决方案2】:

      好像如果你动态添加方法(比如$this->{$name} = function(){})它仍然不能“看到”它

      正确,因为您正在创建一个新的属性,而不是一个方法。在撰写本文时,PHP 不支持在不经过 __call 的情况下调用属性中的匿名函数,这对反射不友好。具有匿名功能的属性作为方法在 PHP 5.4 中正常工作。

      将方法添加到类中的唯一另一种方法是使用 highly experimental "runkit" extension

      【讨论】:

        猜你喜欢
        • 2017-09-05
        • 2010-12-03
        • 2012-11-12
        • 1970-01-01
        • 2012-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-20
        相关资源
        最近更新 更多