繁体   English   中英

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

[英]PHP5.3: “Call to undefined method” error when calling invoke from class variable

我一直在使用__invoke magic方法进行一些测试(以替换旧代码),但我不确定这是否是错误:

假设我们有一个类:

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);

PHP认为您要在实例$ t上调用方法k:

$t->k(4, 5)

这是完全合理的。 您可以使用中间变量来调用对象:

$b = $t->k;
$b(4, 5);

另请参见错误#50029 ,它描述了您的问题。

当您执行$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();

您不能使用方法语法(例如$ foo-> bar())来通过__invoke调用闭包或对象,因为引擎始终认为这是方法调用。 您可以通过__call模拟它:

function __call($name, $params) {
  if(is_callable($this->$name)) {
    call_user_func_array($this->$name, $params);
  }
}

但它不能按原样工作。

如果您调用$ test-> k(),PHP将在$ test实例上搜索一个名为“ k”的方法,显然它将引发Exception。

要解决此问题,您可以创建属性“ 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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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