2012-06-24 28 views
0

我似乎已經在PHP擴展靜態類的麻煩。在PHP擴展靜態類 - 避免了多個類別的共享變量擴展類

PHP代碼:

<?php 
    class InstanceModule { 
     public static $className = 'None'; 
     public static function PrintClassName() { 
      echo self::$className . ' (' . __CLASS__ . ')<br />'; 
     } 
    } 

    class A extends InstanceModule { 
     public static function Construct() { 
      self::$className = "A"; 
     } 
    } 

    class B extends InstanceModule { 
     public static function Construct() { 
      self::$className = "B"; 
     } 
    } 
?> 

我的調用代碼,以及我所期待:

<?php 
    //PHP Version 5.3.14 

    A::PrintClassName(); //Expected 'None' - actual result: 'None' 
    B::PrintClassName(); //Expected 'None' - actual result: 'None' 

    A::Construct(); 

    A::PrintClassName(); //Expected 'A' - actual result: 'A' 
    B::PrintClassName(); //Expected 'None' - actual result: 'A' 

    B::Construct(); 

    A::PrintClassName(); //Expected 'A' - actual result: 'B' 
    B::PrintClassName(); //Expected 'B' - actual result: 'B' 

    A::Construct(); 

    A::PrintClassName(); //Expected 'A' - actual result: 'A' 
    B::PrintClassName(); //Expected 'B' - actual result: 'A' 
?> 

實際完成輸出:

None (InstanceModule) 
None (InstanceModule) 
A (InstanceModule) 
A (InstanceModule) 
B (InstanceModule) 
B (InstanceModule) 
A (InstanceModule) 
A (InstanceModule) 

所以這裏發生了什麼(從看起來)是,只要我在任何一個擴展類上設置self::$className,它就會覆蓋var可以從其他班上學習。我想這是因爲我使用靜態類,只能有,而不是簡單地將其複製到兩個AB一個InstanceModule類,因爲是我以前的extends理解。我試過使用關鍵字static::$className來代替,但似乎沒有區別。

如果有人能指引我在這裏做錯的正確方向,以及如何解決這個問題,這將是可愛的。

編輯: 要澄清,這個代碼我想要做什麼,但顯然是一個可怕的解決辦法,因爲這會毀了擴展和重用功能的整體思路:

<?php 
    class A { 
     public static $className = 'None'; 
     public static function PrintClassName() { 
      echo self::$className . ' (' . __CLASS__ . ')<br />'; 
     } 
     public static function Construct() { 
      self::$className = "A"; 
     } 
    } 

    class B { 
     public static $className = 'None'; 
     public static function PrintClassName() { 
      echo self::$className . ' (' . __CLASS__ . ')<br />'; 
     } 
     public static function Construct() { 
      self::$className = "B"; 
     } 
    } 
?> 

回答

2

因爲$的className是靜態的,並且在父類中,當您在A或B中設置className時,它會更改父代中的變量,並且在讀取變量時完成相同的操作。除非您在擴展類中重寫className,否則將從最初在InstanceModule中定義的相同內存位置存儲和檢索信息。

如果在A/B類名重新定義,則可以分別使用父::或自::從InstanceModule或A/B類名訪問。取決於你想要做什麼,抽象類也可能發揮重要作用。

見在PHP5手冊Static KeywordClass Abstraction

+0

類抽象似乎並沒有讓我的不同(雖然,我可能會做是錯誤的)。正如在OP中提到的,我已經嘗試過使用'static'關鍵字,並且最後在兩個擴展類中重新定義className('public static $ className ='None')實際上導致'PrintClassName()'輸出'None '儘管'self :: $ className'仍然在被定義。 – h2ooooooo

0

我認爲最好的答案,您的情況是使用get_called_class()功能而非目前$className變量,這將返回,而不是__CLASS__get_class()這隻會返回當前類名的後期靜態綁定的類名稱。

如果您將PrintClassName()函數更改爲僅輸出返回的get_called_class(),則輸出如下所示。現在,您只需要合併一個默認值,這當然會在類中共享,所以如果要繼續使用靜態方法,則必須在兩個類中都有該標誌。

A 
B 
A 
B 
A 
B 
A 
B 
+0

當然,A和B只是一種顯示發生了什麼的形式。在我的實際場景中,我處理不同的'extends InstanceModule'類,但它們具有不同的功能(並且它們的常用功能在'InstanceModule'中)。這意味着當我構造類「B」,並嘗試訪問'A :: FunctionInAClass'時,我得到一個錯誤,看到這個函數不存在(因爲此時它確實只有'A :: FunctionInBClass',即使這個函數是在'B'中聲明的,而不是'A'(但是'A'被'B'覆蓋,就像在我的OP例子中一樣) – h2ooooooo

+0

看起來像你最好把這些類改爲靜態的,所以你可以在它們上實例化對象,然後產生你正在尋找的繼承 – nickb

+0

事實上,它實際上是我嘗試調用類(和實例)的一種更全局的方式,當然我可以調用'$ db = DB :: GetInstance(); $ db-> Connect();',但是我在代碼中試圖做的是有一個簡單地使用當前實例的包裝器,然後當你運行'DB ::連接',它在背景中做這個東西。因此,這個問題出現了。我想我必須解決或者使用'$ GLOBALS'(yuck)或必須得到我每當我需要打電話給這個班的時候。 – h2ooooooo

0

我將有基類保持子類的實例的存儲庫,這樣就可以屬於每一類,而不是從一個靜態的基類變量拉動數據正確地單獨的數據。

您可以在基類上使用__callStatic()魔術方法來完成對不存在的子類的調用方法,如下所示。不幸的是,由於該魔術方法的可見性,靜態存儲庫變量需要聲明爲public。

abstract class Base 
{ 
    public static $repo = array(); 

    public static function __callStatic($name, $args) 
    { 
     $class = get_called_class(); 

     if (!isset(self::$repo[$class])) { 
       echo "Creating instance of $class\n"; 
       self::$repo[$class] = new $class(); 
     } 

     return call_user_func_array(array(self::$repo[$class], $name), $args); 
    } 

     protected function PrintClassName() 
     { 
       echo __CLASS__, " (", get_called_class(), ")\n"; 
     } 

     protected abstract function Construct($a); 
} 

class A extends Base 
{ 
     protected function Construct($a) 
     { 
       echo __CLASS__, ": setting x := $a\n"; 
     } 
} 

class B extends Base 
{ 
     protected function Construct($a) 
     { 
       echo __CLASS__, ": setting y := $a\n"; 
     } 
} 

A::PrintClassName(); 
B::PrintClassName(); 

A::Construct('X'); 
B::Construct('Y'); 

輸出:

Creating instance of A 
Base (A) 
Creating instance of B 
Base (B) 
A: setting x := X 
B: setting y := Y