7

假设我们有如下代码:

<?php
class Worker {
  public function __invoke() {
    echo "invoked\n";
  }
}

class Caller {
  public $worker;

  public function __construct($worker) {
    $this->worker = $worker;
  }

  public function __call($name, $arguments) {
    echo "called\n";
  }
}

$c = new Caller(new Worker());
echo $c->worker();
?>

结果是called。做什么才能得到invoked

4

4 回答 4

4

这个问题也存在于同样工作的匿名函数中。您有几种解决方法:

1)修改您的 __call 以检查它是否是一种方法,如果不是,则调用该属性:

if (property_exists($this, $name) && is_object($this->$name) && method_exists($this->$name, "__invoke")) {
    call_user_func_array($this->name, $args);
}

2)__invoke直接调用:$c->worker->__invoke();

3)将属性保存到临时变量中:

$tempVar = $c->worker;
$tempVar();

4)(几乎与 3 相同)(来源:http ://marc.info/?l=php-internals&m=136336319809565&w=4 )

${'_'.!$_=$c->worker}();

5) 使用call_user_funccall_user_func_array

call_user_func($c->worker);
于 2013-05-28T14:08:36.573 回答
2

更新:

如果您不想在所有 Callables 上实现 __call() 方法,我只需像这样扩展 Callable :

<?php
class Worker {
  public function __invoke() {
    echo "invoked\n";
  }
}

class InvokeCaller{

    public function __call($name, $arguments) {
        if(property_exists($this, $name) && is_object($this->{$name}))
            $this->{$name}->__invoke($arguments);
        else
            echo "called\n";
    }

}

class Caller extends InvokeCaller{
  public $worker;

  public function __construct($worker) {
    $this->worker = $worker;
  }

}

class AnotherCaller extends InvokeCaller{

    public $anotherWorker;

    public function __construct($worker) {
        $this->anotherWorker = $worker;
    }

}

$c = new Caller(new Worker());
$c2 = new AnotherCaller(new Worker());
echo $c->worker();
echo $c2->anotherWorker();
?>

老的

我想出了这个

<?php
class Worker {
  public function __invoke() {
    echo "invoked\n";
  }
}

class Caller {
  public $worker;

  public function __construct($worker) {
    $this->worker = $worker;
  }

  public function __call($name, $arguments) {
    if(property_exists($this, $name) && is_object($this->{$name}))
        $this->{$name}->__invoke($arguments);
    else
        echo "called\n";
  }
}

$c = new Caller(new Worker());
echo $c->worker();
?>

我们只是在修改我们的调用。

于 2013-05-28T14:13:18.623 回答
2

我遇到了同样的问题,并且(如您所见)很难说出您的意思是哪个对象。

唯一的方法(即“几乎”清楚)是使用辅助变量

$temp = $c->worker;
$temp(); // should be now invoked
于 2013-05-28T14:07:41.533 回答
0

如果拉取请求将被接受,我们将获得如下语法:

echo ($c->worker)(); //outputs "invoked"
于 2013-06-05T09:12:13.630 回答