2009-02-10 121 views
27

在PHP中,如果在父類中定義了靜態屬性,那麼它不能在子類中重寫。但我想知道是否有任何解決方法。PHP中靜態成員的繼承

我想爲別人的(有點笨重的)函數編寫一個包裝。有問題的函數可以應用於許多不同的數據類型,但每個都需要不同的標誌和選項。但99%的時間,每種類型的默認值就足夠了。

這將是很好,如果這可以用繼承來完成,而不必每次都寫新功能。例如:

class Foo { 
    public static $default = 'DEFAULT'; 

    public static function doSomething ($param = FALSE) { 
     $param = ($param === FALSE) ? self::$default : $param; 
     return $param; 
    } 
} 

class Bar extends Foo { 
    public static $default = 'NEW DEFAULT FOR CHILD CLASS'; 
} 

echo Foo::doSomething() . "\n"; 
// echoes 'DEFAULT' 

echo Bar::doSomething() . "\n"; 
// echoes 'DEFAULT' not 'NEW DEFAULT FOR CHILD CLASS' 
// because it references $default in the parent class :(

回答

15

爲什麼使用靜態的全局變量(在這種情況下函數)的經典例子是一個壞主意,不管語言。

最健壯的方法是創建一個抽象基類「Action」類的多個實現子類。

然後嘗試去除實例化類的一個實例以調用它的方法的一些煩惱,可以將它包裝在某種工廠中。

例如:

abstract class AbstractAction { 
    public abstract function do(); 
} 

class FooAction extends AbstractAction { 
    public function do() { 
    echo "Do Foo Action"; 
    } 
} 

class BarAction extends AbstractAction { 
    public function do() { 
    echo "Do Bar Action"; 
    } 
} 

然後創建一個工廠,在函數的實例化 「援助」

class ActionFactory { 
    public static function get($action_name) { 
    //... return AbstractAction instance here 
    } 
} 

然後用它作爲:

ActionFactory::get('foo')->do(); 
27

即將推出的PHP 5.3.0版本包括late static binding,這可能有所幫助。使用這個特性你可以在一個靜態方法中使用一個靜態變量,讓後期的靜態綁定負責找到「正確」的方法。

class Foo { 
    public static function getDefault() { 
     static $default = 'DEFAULT'; 
     return $default; 
    } 
    public static function doSomething ($param) { 
     $default=static::getDefault(); // here is the late static binding 
     $param = ($param === FALSE) ? $default : $param; 
     return $param; 

    } 
} 

class Bar extends Foo { 
    public static function getDefault() { 
     static $default = 'NEW DEFAULT FOR CHILD CLASS'; 
     return $default; 
    } 
} 
+1

這將是可愛的,感謝您的信息。但是,唉,我需要一些能夠在我當前的生產環境中運行的東西(5.2.6)。謝謝! – PartialOrder 2009-02-10 16:53:48

24

其實我覺得它是不正確的:你可以ovverride靜態propeties(你需要> = 5.3 PHP)。但你必須爲靜態屬性refrencing時要小心(這是在原來代碼中的錯誤)

您需要使用靜:: $ myStaticProperty,而不是使用自:: $ myStaticProperty

self ::將參考當前類所以如果你在一個繼承的靜態方法內,這將引用該類的靜態屬性定義該方法!當使用引用關鍵字static ::將像$ this一樣運行時 - 當您使用實例方法/ propeties時。

在您的示例中,doSomething()是類Bar中的繼承的靜態方法。由於您使用了self ::,它將引用Foo類的靜態屬性。這就是爲什麼你沒有看到任何區別... 嘗試改變自我::靜態::

這是一個代碼示例 - 我自己用它來測試這些事情。我們有靜態屬性/方法繼承,重寫和值更改 - 運行它,你會看到結果!

class A { 

    // a static property - we will test override with it 
    protected static $var = 'class A var - override'; 
    // a static property - we will test value overwrite with it 
    protected static $var2 = 'class A var2 - value overwrite'; 


    public static function myStaticOverridePropertyTest() { 
     return static::$var; 
    } 
    public static function myStaticValueOverwritePropertyTest() { 
     return static::$var2; 
    } 

    /** 
    * This method is defined only here - class B will inherit this one! 
    * We use it to test the difference btw self:: and static:: 
    * 
    * @return string 
    */ 
    public static function myStaticMethodTest() { 
     //return self::getValue(); 
     return static::getValue(); 
    } 

    /** 
    * This method will be overwritten in class B 
    * @return string 
    */ 
    protected static function getValue() { 
     return 'value from class A'; 
    } 
} 


class B extends A { 

    // we override this inherited static property 
    protected static $var = 'class B var - override'; 

    /** 
    * This method is overwritten from class A 
    * @return string 
    */ 
    protected static function getValue() { 
     return 'value from class B'; 
    } 

    /** 
    * We modify the value of the inherited $var2 static property 
    */ 
    public static function modStaticProperty() { 
     self::$var2 = 'class B - altered value! - value overwrite'; 
    } 
} 

echo ("-- testing class A:\n"); 
echo (A::myStaticOverridePropertyTest(). "\n"); 
echo (A::myStaticValueOverwritePropertyTest(). "\n"); 
echo (A::myStaticMethodTest(). "\n"); 

echo ("-- now testing class B:\n"); 
echo (B::myStaticOverridePropertyTest(). "\n"); 
echo (B::myStaticValueOverwritePropertyTest(). "\n"); 
echo (" now invoking B::modStaticProperty()  .\n"); 
B::modStaticProperty(); 
echo (B::myStaticValueOverwritePropertyTest(). "\n"); 

echo ("-- now re-testing class A:\n"); 
echo (A::myStaticOverridePropertyTest(). "\n"); 
echo (A::myStaticValueOverwritePropertyTest(). "\n"); 
echo (A::myStaticMethodTest(). "\n"); 

這將輸出:

- 測試A級:
A類變種 - 覆蓋
A類VAR2 - 值覆蓋從A級

價值 - 現在測試類B:
class B var - 覆蓋
class A var2 - 覆蓋值
現在調用B :: modStaticProperty()...
B類 - 改變價值! - 值覆蓋
- 現在重新測試A類:
A類var - 覆蓋
B類 - 改變的值! - 值覆蓋從類
值A

我們在這裏,你可以看到被覆蓋的,只值覆蓋靜態屬性的區別...看看輸出線我標有魄力!當我們調用類B的modStaticProperty()時,它也改變了類A中該靜態變量的值。由於該靜態屬性被繼承並且未被覆蓋!想想看...

+0

如果字段是公開的並在外部更改,則不起作用。 http://sandbox.onlinephpfunctions.com/code/5d5e947898ea3e4f14e742dd9c9792988fd18dac – 2017-04-19 06:40:41