Remplacer les constantes de classe par rapport aux propriétés

99

Je voudrais mieux comprendre pourquoi, dans le scénario ci-dessous, il existe une différence dans la manière dont les constantes de classe sont héritées par rapport aux variables d'instance.

<?php
class ParentClass {
    const TEST = "ONE";
    protected $test = "ONE";

    public function showTest(){
        echo self::TEST;
        echo $this->test;
    }
}

class ChildClass extends ParentClass {
    const TEST = "TWO";
    protected $test = "TWO";

    public function myTest(){
        echo self::TEST;
        echo $this->test;
    }
}

$child = new ChildClass();
$child->myTest();
$child->showTest();

Production:

TWO
TWO
ONE
TWO

Dans le code ci-dessus, ChildClass n'a pas de méthode showTest (), donc la méthode ParentClass showTest () est utilisée par héritage. Les résultats montrent que, puisque la méthode s'exécute sur ParentClass, la version ParentClass de la constante TEST est en cours d'évaluation, alors que comme elle est évaluée dans le contexte ChildClass via l'héritage, la variable membre ChildClass $ test est en cours d'évaluation.

J'ai lu la documentation, mais je ne vois aucune mention de cette nuance. Quelqu'un peut-il m'éclairer?

Tom Auger
la source
WTF? Priorité constante !? Ne faites pas cela! jamais!
qwert_ukg
2
@qwert_ukg En effet. Quelqu'un devrait communiquer cela aux développeurs de PHP. Ou au moins autoriser final...
Luke Sawczak
1
Il y a sûrement des cas d'utilisation assez bons, même pour un
remplacement

Réponses:

194

self::N'est pas compatible avec l'héritage et fait toujours référence à la classe dans laquelle il est exécuté. Si vous utilisez php5.3 +, vous pouvez essayer static::TESTcommestatic:: est compatible avec l'héritage.

La différence est que static::utilise la "liaison statique tardive". Trouvez plus d'informations ici:

http://php.net/manual/en/language.oop5.late-static-bindings.php

Voici un script de test simple que j'ai écrit:

<?php

class One
{
    const TEST = "test1";

    function test() { echo static::TEST; }
}
class Two extends One
{
    const TEST = "test2";
}

$c = new Two();

$c->test();

production

test2
David Farrell
la source
22
+ pour mentionner static::.
Jason McCreary
Impressionnant. Merci pour la clarification et pour fournir les informations supplémentaires sur les liaisons statiques tardives (que je n'ai pas encore digérées).
Tom Auger
3
Puisque ce test()n'est pas une méthode statique, pourquoi ne pas l'utiliser $this::TESTavec PHP5.3 +?
Xenos
Salut @Xenos - Le but de l'exemple était de montrer que le code au niveau de l'instance s'exécutant dans la classe One récupérait des valeurs statiques de la classe Two. self :: TEST aurait renvoyé "test1" où static :: TEST renvoie le "test2" attendu - J'espère que cela aide, merci d'avoir répondu!
David Farrell
Salut @DavidFarrell - Oui, j'ai la différence self::/ static::mais je ne comprends pas pourquoi utiliser static::au lieu de $this::(pas self::). Y a-t-il une différence entre $this::et static::(puisqu'il y en a un entre static::/ $this::et self::)?
Xenos
17

En PHP, self fait référence à la classe dans laquelle la méthode ou la propriété appelée est définie. Donc , dans votre cas , vous appelez selfà ChildClass, il utilise la variable de cette classe. Ensuite, vous utilisez selfin ParentClass, donc il fera référence à la variable de cette classe.

si vous souhaitez toujours que la classe enfant remplace celle constde la classe parent, ajustez le code suivant dans votre classe parent à ceci:

public function showTest(){
    echo static::TEST;
    echo $this->test;
}

Notez le staticmot - clé. Ceci utilise une "liaison statique tardive". Maintenant, votre classe parent appellera le const de votre classe enfant.

w00
la source
pro. static :: fait un travail dans l'abstraction au lieu de soi ::
Błażej Krzakala