Substituindo constantes de classe vs propriedades

99

Gostaria de entender melhor por que, no cenário abaixo, há uma diferença na maneira como as constantes de classe são herdadas e as variáveis ​​de instância.

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

Resultado:

TWO
TWO
ONE
TWO

No código acima, ChildClass não tem um método showTest (), portanto, o método ParentClass showTest () é usado por herança. Os resultados mostram que, como o método está sendo executado na ParentClass, a versão ParentClass da constante TEST está sendo avaliada, enquanto, por estar avaliando dentro do contexto ChildClass por meio de herança, a variável de membro ChildClass $ test está sendo avaliada.

Eu li a documentação, mas não consigo ver qualquer menção a essa nuance. Alguém pode lançar alguma luz para mim?

Tom Auger
fonte
WTF? Substituição constante !? Não faça isso! Nunca!
qwert_ukg
2
@qwert_ukg Certamente. Alguém deveria comunicar isso aos desenvolvedores de PHP. Ou pelo menos permitir final...
Luke Sawczak
1
Com certeza, existem casos de uso bons o suficiente, mesmo para substituição constante:]
Arziel

Respostas:

194

self::Não é ciente de herança e sempre se refere à classe em que está sendo executado. Se você estiver usando o php5.3 +, você pode tentar static::TESTcomo static::está ciente de herança.

A diferença é que static::usa "vinculação estática tardia". Encontre mais informações aqui:

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

Aqui está um script de teste simples que escrevi:

<?php

class One
{
    const TEST = "test1";

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

$c = new Two();

$c->test();

resultado

test2
David Farrell
fonte
22
+ para mencionar static::.
Jason McCreary
Impressionante. Obrigado pelo esclarecimento e por fornecer informações adicionais sobre late-static-bindings (que ainda não digeri).
Tom Auger
3
Já que test()não é um método estático, por que não usar $this::TESTcom PHP5.3 +?
Xenos
Olá, @Xenos - O objetivo do exemplo era mostrar que o código de nível de instância em execução na classe Um estava recuperando valores estáticos da classe Dois. self :: TEST teria retornado "test1" onde static :: TEST retorna o esperado "test2" - Espero que ajude, obrigado por responder!
David Farrell
Olá, @DavidFarrell - Sim, entendi a diferença self::/ static::mas não entendi por que usar em static::vez de $this::(não self::). Existe uma diferença entre $this::e static::(uma vez que existe um entre static::/ $this::e self::)?
Xenos
17

Em PHP, self se refere à classe na qual o método ou propriedade chamada é definida. Assim, no seu caso, você está chamando selfem ChildClass, por isso usa a variável a partir dessa classe. Então você usa selfin ParentClass, então ele irá se referir à variável naquela classe.

se você ainda quiser que a classe filha substitua o constda classe pai, ajuste o seguinte código em sua classe pai para isso:

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

Observe a staticpalavra - chave. Isso usa "vinculação estática tardia". Agora sua classe pai chamará const de sua classe filha.

w00
fonte
pró. static :: made job in abstraction em vez de self ::
Błażej Krzakala