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

发布于 2024-09-07 00:26:34 字数 981 浏览 4 评论 0原文

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

让我们假设我们有一个类:

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

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:

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

吻风 2024-09-14 00:26:34

当您这样做时,PHP 认为您想在实例 $t 上调用方法 k:

$t->k(4, 5)

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

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

另请参阅 bug #50029,这描述了您的问题。

PHP thinks you want to call a method k on instance $t when you do:

$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.

绳情 2024-09-14 00:26:34

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

When you do $test->k(), PHP thinks you are calling a method on the $test instance. Since there is no method named k(), PHP throws an exception. 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. 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:

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.

But anyway, then you can do

$test->k();
风向决定发型 2024-09-14 00:26:34

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

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

但它不会按原样工作。

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. You could simulate it through __call:

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

but it would not work as-is.

满天都是小星星 2024-09-14 00:26:34

如果你调用 $test->k() PHP 将在 $test 实例上搜索名为“k”的方法,显然它会抛出异常。

为了解决这个问题,你可以创建属性“k”的 getter

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

If you call $test->k() PHP will search for a method called "k" on the $test instance and obviously it will throws an Exception.

To resolve this problem you can create a getter of the property "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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文