如何在类内调用成员变量的__invoke方法

23

我这里是PHP 5.4.5版本。我尝试调用作为其他对象成员存储的对象。大概是这样的:

class A {
    function __invoke () { ... }
}

class B {
    private a = new A();
 ...
    $this->a();  <-- runtime error here
}

当然,这会产生一个运行时错误,因为没有名为 a 的方法。但是如果我像这样编写调用:

($this->a)();
然后我收到了语法错误提示。
当然,我可以写

$this->a->__invoke();

但是那看起来实在太丑陋了,而且有些破坏了函数对象的意义。我只是想知道是否有更好(或者官方)的方法。

3个回答

29

有三种方式:

直接调用__invoke,就像你已经提到的那样:

$this->a->__invoke();

通过将值分配给变量:

$a = $this->a;
$a();

通过使用call_user_func函数:

call_user_func($this->a);

最后一个可能是您正在寻找的。它的好处是它可以与任何可调用对象一起使用。


1
谢谢Igor。在这三种方式中,将变量赋值似乎是最清晰的,但它们都不太好。有人能理解为什么“显然”的语法$this->a()无法找到成员的__invoke方法吗?为什么成员访问在本质上与裸变量语法不同? - Jules May
2
因为它是模棱两可的。$this->a() 可以是方法 a 或成员 $a。在 PHP 中,这两者分别被严格区分(不像 JavaScript)。 - igorw

13

提醒,在PHP 7+中,对象内回调函数的括号现在有效了:

class foo {                                                                     
    public function __construct() {                                             
        $this -> bar = function() {                                             
            echo "bar!" . PHP_EOL;                                              
        };                                                                      
    }                                                                           

    public function __invoke() {                                                
        echo "invoke!" . PHP_EOL;                                               
    }                                                                           
}                                                                               

(new foo)();                                                                    

$f = new foo;                                                                   
($f -> bar)(); 

结果:

invoke!
bar!

5

我知道这个回答有点晚了,但可以在父类中使用 __call() 方法和在子类中使用 __invoke() 方法的组合:

class A {
  function __invoke ($msg) {
    print $msg;
  }
}

class B {
    private $a;

    public function __construct() { $this->a = new A(); }

    function __call($name, $args)
    {
      if (property_exists($this, $name))
      {
        $prop = $this->$name;
        if (is_callable($prop))
        {
          return call_user_func_array($prop, $args);
        }
      }
    }
}

那么你应该能够实现你正在寻找的语法糖:
$b = new B();
$b->a("Hello World\n");

这是一个相当巧妙的方法。谢谢。 - Jules May

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接