2009-02-10 11 views
27

En PHP, si un attribut statique est défini dans la classe parent, il ne peut pas être substitué dans une classe enfant. Mais je me demande s'il y a un moyen de contourner cela. J'essaye d'écrire une enveloppe pour la fonction de quelqu'un d'autre (quelque peu maladroite). La fonction en question peut être appliquée à un grand nombre de types de données différents, mais nécessite des indicateurs et des options différents pour chacun. Mais 99% du temps, un défaut pour chaque type suffirait.Héritage des membres statiques dans PHP

Ce serait bien si cela pouvait être fait avec l'héritage, sans avoir à écrire de nouvelles fonctions à chaque fois. Par exemple:

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

Répondre

15

exemple classique des raisons pour lesquelles l'utilisation GLOBALS (comme statics fonctions dans ce cas) est une mauvaise idée, peu importe la langue.

La méthode la plus robuste consiste à créer plusieurs sous-classes d'implémentation d'une classe "Action" de base abstraite. Ensuite, pour essayer de supprimer une partie de l'ennui d'instancier une instance de la classe juste pour appeler ses méthodes, vous pouvez l'enrouler dans une fabrique quelconque.

Par exemple:

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

Ensuite, créez une usine à "l'aide" dans une instanciation de la fonction

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

ensuite l'utiliser comme:

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

Le PHP 5.3.0 prochaine version inclut late static binding, ce qui pourrait aider. En utilisant cette fonctionnalité, vous pouvez utiliser une variable statique dans une méthode statique, et laisser la liaison statique tardive prendre soin de trouver la bonne méthode.

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

Ce serait charmant et merci pour l'info. Mais hélas, j'ai besoin de quelque chose qui fonctionnera dans mon environnement de production actuel (5.2.6). MERCI! – PartialOrder

24

En fait, je pense que n'est pas vrai: vous pouvez renverser les propriétés statiques (vous avez besoin> = 5.3 PHP pour ça). Mais vous devez être prudent lorsque vous refrencing pour cette propriété statique (ce qui est l'erreur dans le code d'origine)

Vous devez utiliser statique :: myStaticProperty $ au lieu d'utiliser l'auto :: myStaticProperty $

self :: réfrénera au classe actuelle donc si vous êtes dans une méthode statique héritée cela réfrénera la propriété statique de cette classe définie cette méthode! Tout en utilisant le mot clé de référence static :: agira comme $ this - lorsque vous utilisez des méthodes/propriétés d'instance. DoSomething() est une méthode statique héritée de la classe Bar dans votre exemple.


Comme vous avez utilisé self :: there, il fera référence à la propriété statique de la classe Foo. C'est la raison pour laquelle vous n'avez pas vu de différence ... Essayez de changer de soi :: à statique ::!

Voici un exemple de code - Je l'ai utilisé moi-même pour tester ces choses. Nous avons la propriété statique/héritage de la méthode, le remplacement et le changement de valeur - exécutez-le et vous verrez le résultat!

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

Affichera:

- classe test A:
classe A var - override
classe A var2 - valeur écrasera
valeur de la classe A
- classe maintenant tester B:
classe B var - override
classe A var2 - écrasement de valeur
invoquant maintenant B :: modStaticProperty() ...
classe B - valeur modifiée! - écraser la valeur
- re-tester maintenant classe A:
classe A var - override
classe B - valeur modifiée! - écraser la valeur
valeur de la classe A

Et nous voilà, vous pouvez voir la différence entre les propriétés statiques substituées et remplacées uniquement ... regardez la ligne de sortie que j'ai marquée en gras! Lorsque nous avons appelé le modStaticProperty() de la classe B, il a également changé la valeur de cette variable statique dans la classe A. Puisque cette propriété statique a été héritée et n'a pas été annulée! Pensez-y ...

+0

Ne fonctionnera pas si les champs sont publics et modifiés à l'extérieur. http://sandbox.onlinephpfunctions.com/code/5d5e947898ea3e4f14e742dd9c9792988fd18dac –

+0

TL; DR: Vous devez utiliser 'static :: $ myStaticProperty' au lieu d'utiliser' self :: $ myStaticProperty';) – T30

Questions connexes