2012-08-05 19 views
1

我得到了一些奇怪的結果,最好通過顯示代碼來解釋。當使用__callStatic函數時奇怪的遞歸結果

說我創造它有3種方法A類:
添加方法 - 添加其他的A類實例在以後的時間
_ 呼叫魔術方法中使用 - 添加動態VAR和有值
_callStatic靜態魔術方法 - 這種方法幫助我創建一個類更具可讀性

,所以這個類是:

class A_Class { 

protected $name; 
protected $varList; 
protected $childs = array(); 

protected static $tabCount = 0; 

public function __construct($name) { 
    $this->name = $name; 
} 

public function add() { 
    if (func_num_args()) { 
     $this->childs = array_merge($this->childs, func_get_args()); 
    } 
    return $this; 
} 

public function __call($name, $arguments) { 
    if (count($arguments) > 0) { 
     $this->varList[$name] = $arguments[0]; 
    } 
    return $this; 
} 

public static function __callStatic($name, $arguments) { 
    return new A_Class($name); 
} 

} 

,現在當我使用它:

$a = A_Class::MyNameA(); 
$a->someDynamicVar("I am the var data"); 
$a->add(A_Class::ANotherNameA()); 
print_r($a); 

作品就好導致:

A_Class Object 
(
    [name:protected] => MyNameA 
    [varList:protected] => Array 
     (
      [someDynamicVar] => I am the var data 
     ) 

    [childs:protected] => Array 
     (
     ) 
) 

但是,如果我嘗試創建B類從A類繼承,像這樣:

class B_Class extends A_Class { 

public function __construct($name) { 
    parent::__construct($name); 
    $this->add(A_Class::NewAClass()); 
} 

} 

並嘗試以下操作:

$b = new B_Class("NewBClassInstance"); 
print_r($b); 

我得到一個遞歸的結果:

B_Class Object 
(
    [name:protected] => B-MAN 
    [varList:protected] => 
    [childs:protected] => Array 
     (
      [0] => B_Class Object 
*RECURSION* 
     ) 
) 

,我認爲是奇怪的。
這是因爲如果__callStatic正在從B類運行而不是A類

有什麼想法?

+0

我覺得很奇怪,在varList中沒有包含A_Class實例的行'add',不是? – 2012-08-05 17:41:34

回答

1

也許這個例子可以幫助你理解:

<?php 

class A 
{ 
    public function __call($name, $args) 
    { 
    echo "__call\n"; 
    } 

    static public function __callStatic($name, $args) 
    { 
    echo "__callStatic\n"; 
    } 
} 

class B extends A 
{ 
    public function __construct() 
    { 
    A::callMe(); 
    } 
} 

new B(); 

運行此的結果是:

__call 

它確實調用靜態版本。爲什麼?因爲B從A下降,因此當存在__call__callStaticA::foo()是模糊的呼叫。

請記住,一類Class::func()意味着「調用名爲Classfunc靜態方法」的成員函數的範圍內。

它只是表示「致電Class的函數func」。例如:

class A 
{ 
    public function foo() {} 
} 

class B 
{ 
    public function foo() {} 

    public function bar() 
    { 
    A::foo(); // call A's foo 
    } 
} 

所以你的情況,該__call方法被稱爲B的構造函數。這正是PHP在這種模糊的情況下所做的。它返回$this這是傳遞到$this->add(),有效地給你這個:在B的構造函數中$this->add($this)

再次,這些都不指類的上下文中「調用靜態功能」成員函數:

parent::foo(); 
self::foo(); 
static::foo(); 
A::foo(); 
B::foo(); 

它們都只是意味着「類中的通話功能富被作爲參考::「的左邊。通常你要麼有明確的實例函數,要麼有靜態函數,所以調用不是不明確的。但是,當您同時使用__call__callStatic時,PHP無法知道您想要調用哪個,並且它始終選擇__call

+0

謝謝。 雖然我明白你的答案,但我不明白這個邏輯。我的小理解似乎是一個錯誤的設計 – Yair 2012-08-06 06:38:34

+0

關鍵的一點是,當出現在類的派生自類的任何實例方法內部的'Foo :: bar()'並不意味着「調用靜態方法名爲'bar'」 Foo'。這不是PHP的錯;這是一個功能。你還有什麼可以在繼承層次中調用特定的方法?唯一不明確的是如果你同時擁有'__call'和'__callStatic'。除非絕對需要,否則我建議不要使用這兩種魔法中的任何一種。在你的情況下,只需創建一個名爲'A :: withName($ name)'的靜態方法,並將其稱爲'A_Class :: withName('NewAClass')'。更容易理解。 – Matthew 2012-08-06 06:44:53