为什么从对象属性触发时PHP`__invoke`无法正常工作

Tau*_*man 2 php

我想知道这是错误还是正常。假设我有一类具有一些神奇功能的类:

class Foo {
    public function __toString() {
        return '`__toString` called.';
    }
    public function __get($key) {
        return '`__get(' . $key . ')` called.';
    }
    public function __invoke($x = "") {
        return '`__invoke(' . $x . ')` called.';
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在对象属性中创建一个实例,如下所示:

$object = (object) [
    'foo' => 'bar',
    'baz' => new Foo
];
Run Code Online (Sandbox Code Playgroud)

然后测试一下:

echo $object->baz;
echo $object->baz->qux;
echo $object->baz('%'); // :(
Run Code Online (Sandbox Code Playgroud)

在最后一个回声中它被打破了: Call to undefined method stdClass::baz()

当前,我唯一能做的解决方案是将__invoke零件存储在一个临时变量中,然后将该变量作为如下函数调用:

$x = $object->baz;
echo $x('%'); // :)
Run Code Online (Sandbox Code Playgroud)

当我在array属性中实例化该类时,它可以正常工作:

$array = [
    'baz' => new Foo
];

echo $array['baz'];
echo $array['baz']->qux;
echo $array['baz']('%'); // :)
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我需要在对象上具有与API相关的某些功能:

$foo = (object) ['bar' => new MyClass];
Run Code Online (Sandbox Code Playgroud)
  • echo $foo->bar;?应该触发__toString
  • echo $foo->bar->baz;?应该触发__get
  • echo $foo->bar();?应该触发__invoke
  • echo $foo->bar->baz();?应该触发__call

他们都应该返回一个字符串。

可以完全用PHP完成吗?谢谢。

Nar*_*arf 5

没办法

问题所在的行简直是模棱两可,错误消息向您展示了如何...尝试访问对象的baz()方法更合乎逻辑$object
那只是解析器看到的上下文$object->baz()

正如评论中已经提到的那样,您可以消除这种歧义,通过告诉它$object->baz本身是一个需要首先执行的表达式来帮助解析器:

($object->baz)('arg');
Run Code Online (Sandbox Code Playgroud)

PHP本身也是一个程序,在执行之前必须知道如何执行某些操作。如果它可以盲目地尝试$foo->bar->baz->qux链中每个对象的所有可能的“魔术”方法,那么它将无法告诉您遇到错误时的错误-它将以静默方式崩溃。

  • 是的,这只是`$ var = $ object-> baz的简写;$ var('arg');`。它在PHP 7之前不起作用,但是无论如何您都应该尽快转向该版本。 (2认同)