2010-06-24 65 views
6

我一直在用__invoke魔术方法进行一些测试(替换旧代码),我不确定这是否是一个错误:PHP5.3:调用类变量调用时调用“未定义的方法”错误

让我们假设有一个类:

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

我知道,一个“解决方案”可能是有类测试中的功能(名为k)使用call_user_func_array“转发”该呼叫,但这不够优雅。

我需要将该实例保存在一个公共类(用于设计目的)中,并且能够将其作为其他类的函数调用......任何建议?

更新:

我发现了一些有趣的事情(我的目的至少):

如果我们分配“类变量”到一个局部变量它的工作原理:

$t = new Test; 
$m = $t->k; 
echo $m(4,5); 
+0

请提供一个完整的代码示例,显示您的问题。你说的作品的代码示例不起作用,你说的代码示例给出了一个问题。 – Sjoerd 2010-06-24 07:54:29

+0

是的,对不起,我的坏...我更新它。 Sjoerd:这个例子是否适合你?奇怪的:S – lepe 2010-06-24 07:56:10

回答

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(); 
+0

我们同时发布了......是的,也许这可以帮助...如果我没有找到其他更好的替代方案,我会标记你的答案是好的。 – lepe 2010-06-24 08:00:41

6

PHP会认为你想打电话实例$ T K的方法,当你这样做:

$t->k(4, 5) 

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

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

又见bug #50029,这说明您的问题。

+0

+1查找bug – Gordon 2010-06-24 08:07:39

+0

(+1)。现在它已经越来越清晰了。谢谢你的链接。 – lepe 2010-06-24 08:17:30

2

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

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

但它不会按原样工作。

相关问题