我一直在用__invoke魔术方法进行一些测试(替换旧代码),我不确定这是不是一个bug:
假设我们有一个班级:
class Calc {
function __invoke($a,$b){
return $a*$b;
}
}
以下是可能的,并且没有任何问题:
$c = new Calc;
$k = $c;
echo $k(4,5); //outputs 20
但是,如果我想要另一个类来存储该对象的实例, 这不起作用:
class Test {
public $k;
function __construct() {
$c = new Calc;
$this->k = $c; //Just to show a similar situation than before
// $this-k = new Calc; produces the same error.
}
}
当我们尝试调用它时会发生错误:
$t = new Test;
echo $t->k(4,5); //Error: Call to undefined method Test::k()
我知道“解决方案”可能是在类Test(名为k)中使用call_user_func_array来“转发”调用,但这并不优雅。
我需要将该实例保存在公共类中(出于设计目的)并能够将其作为函数从其他类中调用...任何建议?
更新
我发现了一些有趣的东西(至少对我而言):
如果我们将“类变量”分配给局部变量,它可以工作:
$t = new Test;
$m = $t->k;
echo $m(4,5);
答案 0 :(得分:6)
当你这样做时,PHP认为你想在实例$ t上调用方法k:
$t->k(4, 5)
这是完全合理的。您可以使用中间变量来调用对象:
$b = $t->k;
$b(4, 5);
另请参阅bug #50029,其中介绍了您的问题。
答案 1 :(得分:5)
执行$test->k()
时,PHP认为您正在调用$test
实例上的方法。由于没有名为k()
的方法,PHP会引发异常。你要做的是让PHP返回公共属性k
并调用它,但为了这样做,你必须先将k
赋给变量。这是一个解除引用的问题。
您可以将魔术__call
方法添加到Test
类,以检查是否存在具有被调用方法名称的属性,并调用该方法:
public function __call($method, $args) {
if(property_exists($this, $method)) {
$prop = $this->$method;
return $prop();
}
}
我将调用的参数添加到您。
您可能还想检查属性is_callable
。
但无论如何,你可以做到
$test->k();
答案 2 :(得分:2)
您不能使用方法语法(如$ foo-> bar())来使用__invoke调用闭包或对象,因为引擎始终认为这是方法调用。你可以通过__call来模拟它:
function __call($name, $params) {
if(is_callable($this->$name)) {
call_user_func_array($this->$name, $params);
}
}
但它不会按原样运作。
答案 3 :(得分:0)
如果调用$ test-> k(),PHP将在$ test实例上搜索一个名为“ k”的方法,显然它将引发异常。
要解决此问题,您可以创建属性“ k”的吸气剂
class Test {
public $k;
function __construct() {
$c = new Calc;
$this->k = $c; //Just to show a similar situation than before
// $this-k = new Calc; produces the same error.
}
public function getK() {
return $this->k;
}
}
因此,现在您可以通过以下方式使用函子:
$t = new Test();
echo $t->getK()(4,5);