2009-02-10 11 views
27

In PHP, se un attributo statico è definito nella classe padre, non può essere sovrascritto in una classe figlio. Ma mi chiedo se c'è un modo per aggirare questo.Ereditarietà di membri statici in PHP

Sto provando a scrivere un wrapper per la funzione di qualcun altro (un po 'goffo). La funzione in questione può essere applicata a molti tipi di dati diversi ma richiede diversi flag e opzioni per ciascuno. Ma il 99% delle volte, un valore predefinito per ogni tipo sarebbe sufficiente.

Sarebbe bello se questo potesse essere fatto con l'ereditarietà, senza dover scrivere nuove funzioni ogni volta. Per esempio:

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

risposta

15

classico esempio di perchè usando statica come globali (funzioni in questo caso) è una cattiva idea, non importa la lingua.

Il metodo più efficace consiste nel creare più sottoclassi di implementazione di una classe "Action" di base astratta.

Quindi, per provare a rimuovere alcuni dei fastidi di istanziare un'istanza della classe solo per chiamare i suoi metodi, è possibile avvolgerla in una fabbrica di qualche tipo.

Ad esempio:

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"; 
    } 
} 

quindi creare una fabbrica di "aiuti" in istanziazione della funzione

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

quindi utilizzarlo come:

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

L'imminente rilascio di PHP 5.3.0 include late static binding, che potrebbe aiutare. Utilizzando questa funzione è possibile utilizzare una variabile statica all'interno di un metodo statico e lasciare che il binding statico avanzato si occupi di trovare il metodo "giusto".

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

Sarebbe bello e grazie per le informazioni. Ma ahimè, ho bisogno di qualcosa che verrà eseguito nel mio attuale ambiente di produzione (5.2.6). GRAZIE! – PartialOrder

24

In realtà penso che non è vero: puoi ovverride le propensioni statiche (hai bisogno di> = 5.3 PHP per quello). Ma bisogna stare attenti quando si refrencing per quella proprietà statiche (e questo è l'errore nel codice originale)

È necessario utilizzare statica :: $ myStaticProperty invece di usare self :: $ myStaticProperty

self :: si aggiornerà alla classe corrente quindi, se si è all'interno di un metodo statico ereditato, questo refrence la proprietà statica di quella classe definita tale metodo! Durante l'utilizzo della parola chiave di riferimento static :: si comporta come $ this - quando si utilizzano metodi/propties di istanza.

doSomething() è un metodo statico ereditato nella classe Bar nell'esempio. Dal momento che hai usato self :: there, farà riferimento alla proprietà statica della classe Foo. Questo è il motivo per cui non hai visto alcuna differenza ... Prova a cambiare auto :: statico ::!

Ecco un esempio di codice: l'ho usato io stesso per testare queste cose. Abbiamo ereditarietà di proprietà/metodo, override e modifica del valore in esso - eseguilo e vedrai il risultato!

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

Questo stamperà:

- Classe test A:
classe A var - Override
classe A var2 - valore sovrascrive
valore dalla classe A
- classe ora testando B:
classe B var. Override
classe A var2 - sovrascrittura valore
che ora richiama B :: modStaticProperty() ...
classe B - valore alterato! - sovrascrittura valore
- ora testare nuovamente la classe A:
classe A var. override
classe B - valore modificato! - Valore sovrascrivere
valore dalla classe A

Ed eccoci qui, si può vedere la differenza tra il valore sovrascritto proprietà statiche sovrascritte e solo ... cercare la linea di uscita ho segnato con in grassetto! Quando abbiamo invocato modStaticProperty() della classe B, ha modificato anche il valore di tale variabile statica in classe A. Dal momento che quella proprietà statica è stata ereditata e non è stata sostituita! Pensaci ...

+0

Non funziona se i campi sono pubblici e vengono modificati all'esterno. http://sandbox.onlinephpfunctions.com/code/5d5e947898ea3e4f14e742dd9c9792988fd18dac –

+0

TL; DR: È necessario utilizzare 'static :: $ myStaticProperty' invece di usare' self :: $ myStaticProperty';) – T30

Problemi correlati