Zastępowanie stałych klas a właściwości

99

Chciałbym lepiej zrozumieć, dlaczego w poniższym scenariuszu istnieje różnica w sposobie dziedziczenia stałych klas w porównaniu ze zmiennymi instancji.

<?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();

Wynik:

TWO
TWO
ONE
TWO

W powyższym kodzie ChildClass nie ma metody showTest (), więc metoda ParentClass showTest () jest używana przez dziedziczenie. Wyniki pokazują, że ponieważ metoda jest wykonywana na ParentClass, oceniana jest wersja ParentClass stałej TEST, natomiast ponieważ jest ona oceniana w kontekście ChildClass poprzez dziedziczenie, oceniana jest zmienna składowa ChildClass $ test.

Przeczytałem dokumentację, ale nie widzę żadnej wzmianki o tym niuansie. Czy ktoś może rzucić dla mnie trochę światła?

Tom Auger
źródło
WTF? Ciągłe zastępowanie !? Nie rób tego! nigdy!
qwert_ukg
2
@qwert_ukg Rzeczywiście. Ktoś powinien to przekazać twórcom PHP. Albo przynajmniej pozwól final...
Luke Sawczak
1
Z pewnością są wystarczająco dobre przypadki użycia nawet do ciągłego
zastępowania

Odpowiedzi:

194

self::Nie jest świadomy dziedziczenia i zawsze odwołuje się do klasy, w której jest wykonywany. Jeśli używasz php5.3 +, możesz spróbować static::TESTtak, jak static::jest to uwzględniające dziedziczenie.

Różnica polega na tym, że static::używa się „późnego wiązania statycznego”. Więcej informacji znajdziesz tutaj:

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

Oto prosty skrypt testowy, który napisałem:

<?php

class One
{
    const TEST = "test1";

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

$c = new Two();

$c->test();

wynik

test2
David Farrell
źródło
22
+ za wspomnienie static::.
Jason McCreary
Niesamowite. Dziękuję za wyjaśnienie i dodatkowe informacje na temat późnych wiązań statycznych (których jeszcze nie przetrawiłem).
Tom Auger
3
Ponieważ test()nie jest to metoda statyczna, dlaczego nie używać $this::TESTz PHP5.3 +?
Xenos
Cześć @Xenos - Celem przykładu było pokazanie, że kod na poziomie instancji wykonywany w klasie pierwszej pobierał wartości statyczne z klasy drugiej. self :: TEST zwróciłby „test1”, gdzie static :: TEST zwraca oczekiwany „test2” - Mam nadzieję, że to pomoże, dzięki za odpowiedź!
David Farrell
Cześć @DavidFarrell - Tak, dostałem różnicę self::/, static::ale nie rozumiem, dlaczego używam static::zamiast $this::(nie self::). Czy istnieje różnica między $this::istatic:: (ponieważ jest jeden między static::/ $this::a self::)?
Xenos
17

W PHP self oznacza klasę, w której zdefiniowana jest wywoływana metoda lub właściwość. Tak w przypadku, gdy dzwonisz selfw ChildClass, więc używa zmiennej z tej klasy. Następnie używasz selfin ParentClass, więc będzie odwoływać się do zmiennej w tej klasie.

jeśli nadal chcesz, aby klasa podrzędna zastępowała constklasę nadrzędną, dostosuj następujący kod w klasie nadrzędnej do tego:

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

Zwróć uwagę na staticsłowo kluczowe. To jest używane „późne wiązanie statyczne”. Twoja klasa nadrzędna będzie teraz wywoływać const klasy podrzędnej.

w00
źródło
zawodowiec. static :: wykonał pracę w abstrakcji zamiast siebie ::
Błażej Krzakala