[英]PHP5.3: “Call to undefined method” error when calling invoke from class variable
I have been doing some tests (to replace old code) with the __invoke magic method and I'm not sure this is a bug or not: 我一直在使用__invoke magic方法进行一些测试(以替换旧代码),但我不确定这是否是错误:
Lets suppose we have a class: 假设我们有一个类:
class Calc {
function __invoke($a,$b){
return $a*$b;
}
}
The following is possible and works without any problem: 以下是可能的,并且可以正常工作:
$c = new Calc;
$k = $c;
echo $k(4,5); //outputs 20
However if I want to have another class to store an instance of that object, this doesn't work: 但是,如果我想让另一个类存储该对象的实例,则无法正常工作:
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.
}
}
The error occurs when we try to call it like: 当我们尝试像这样调用时会发生错误:
$t = new Test;
echo $t->k(4,5); //Error: Call to undefined method Test::k()
I know that a "solution" could be to have a function inside the class Test (named k) to "forward" the call using call_user_func_array but that is not elegant. 我知道“解决方案”可能是在Test类(名为k)中具有一个函数,以使用call_user_func_array“转发”调用,但这并不优雅。
I need to keep that instance inside a common class (for design purposes) and be able to call it as function from other classes... any suggestion? 我需要将该实例保留在一个公共类中(出于设计目的),并能够从其他类中将其作为函数调用...有什么建议吗?
Update: 更新:
I found something interesting (at least for my purposes): 我发现了一些有趣的东西(至少出于我的目的):
If we assign the "class variable" into a local variable it works: 如果我们将“类变量”分配给局部变量,它将起作用:
$t = new Test;
$m = $t->k;
echo $m(4,5);
PHP thinks you want to call a method k on instance $t when you do: PHP认为您要在实例$ t上调用方法k:
$t->k(4, 5)
which is perfectly reasonable. 这是完全合理的。 You can use an intermediate variable to call the object:
您可以使用中间变量来调用对象:
$b = $t->k;
$b(4, 5);
See also bug #50029 , which describes your issue. 另请参见错误#50029 ,它描述了您的问题。
When you do $test->k()
, PHP thinks you are calling a method on the $test
instance. 当您执行
$test->k()
,PHP认为您正在$test
实例上调用一个方法。 Since there is no method named k()
, PHP throws an exception. 由于没有名为
k()
方法,PHP会引发异常。 What you are trying to do is make PHP return the public property k
and invoke that, but to do so you have to assign k
to a variable first. 您想要做的是使PHP返回公共属性
k
并调用它,但是要这样做,您必须首先将k
分配给变量。 It's a matter of dereferencing. 这是取消引用的问题。
You could add the magic __call
method to your Test
class to check if there is a property with the called method name and invoke that instead though: 您可以将魔术
__call
方法添加到Test
类中,以检查是否存在带有被调用方法名称的属性,并通过以下方式调用该属性:
public function __call($method, $args) {
if(property_exists($this, $method)) {
$prop = $this->$method;
return $prop();
}
}
I leave adding the arguments to the invocation to you. 我将在调用中添加参数。 You might also want to check if the property
is_callable
. 您可能还需要检查属性是否为
is_callable
。
But anyway, then you can do 但是无论如何,你可以做
$test->k();
You can not use method syntax (like $foo->bar() ) to call closures or objects with __invoke, since the engine always thinks this is a method call. 您不能使用方法语法(例如$ foo-> bar())来通过__invoke调用闭包或对象,因为引擎始终认为这是方法调用。 You could simulate it through __call:
您可以通过__call模拟它:
function __call($name, $params) {
if(is_callable($this->$name)) {
call_user_func_array($this->$name, $params);
}
}
but it would not work as-is. 但它不能按原样工作。
If you call $test->k() PHP will search for a method called "k" on the $test instance and obviously it will throws an Exception. 如果您调用$ test-> k(),PHP将在$ test实例上搜索一个名为“ k”的方法,显然它将引发Exception。
To resolve this problem you can create a getter of the property "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;
}
}
So now you can use the functor in this way: 因此,现在您可以按以下方式使用函子:
$t = new Test();
echo $t->getK()(4,5);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.