PHP ReflectionClass hasMethod 和 __call()

发布于 2024-10-31 12:12:39 字数 252 浏览 1 评论 0原文

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

I'm creating a dynamic class that responds to magic __call() method. The problem is, since I'm building this on top of a already existing framework (Kohana), it checks if the method of the class exists using ReflectionClass::hasMethod, and it doesn't seem to trigger the __call() magic method for checking for it's existance. What could I do in this case? Seems like if you add the method dynamically (like $this->{$name} = function(){}) it still can't "see" it

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

屌丝范 2024-11-07 12:12:39

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

   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 魔法,以将属性访问/变异调用转发到内部对象(或在代理中处理它们,不管怎样

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

Without more details, I'm unsure if this would suffice, however you could create proxy class to perform intermediate functionality:

   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);
    }

}

By calling $proxy->setMethod('foo', function () { });, you can dynamically "attach" methods to the object. When you call $proxy->foo(), it'll first do a look-up against the dynamically attached methods; if it finds one, it'll call it. Otherwise, it'll just delegate to the internal object.

Now, the problem with this approach is that attached methods aren't bound to the proxy. In other words, $this doesn't exist in the scope of an attached method.

This can be fixed though, with features from PHP 5.4+.

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

We've refined setMethod to rebind the passed closure to the proxy. Now, in the scope of an attached method, $this will point to the proxy object.

We could have rebound it to the enclosed object, but then the attached methods couldn't talk to the proxy (or other attached methods). For completeness, you'll want to add __get and __set magic, to forward property access/mutate calls to the internal object (or handle them in the proxy, whatever)

Besides, the internal object has no clue about the proxy, so it's methods (from the class definition) won't know about any of this dynamic magic anyway.

黒涩兲箜 2024-11-07 12:12:39

似乎如果您动态添加该方法(例如 $this->{$name} = function(){}) 它仍然无法“看到”它

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

以反射将采用的方式向类添加方法的唯一其他方法是使用 高度实验性的“runkit”扩展

Seems like if you add the method dynamically (like $this->{$name} = function(){}) it still can't "see" it

Right, as you're creating a new property, not a method. At time of writing, PHP did not support calling anonymous functions in properties without going through __call, which isn't Reflection-friendly. Properties-with-anonymous-functions-as-methods work properly in PHP 5.4.

The only other way to add a method to a class in a way that Reflection will pick up on is using the highly experimental "runkit" extension.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文