简体   繁体   English

PHP5.3:从类变量调用调用时出现“调用未定义方法”错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM