Anulación de constantes de clase frente a propiedades

99

Me gustaría comprender mejor por qué, en el escenario siguiente, hay una diferencia en la forma en que se heredan las constantes de clase frente a las variables de instancia.

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

Salida:

TWO
TWO
ONE
TWO

En el código anterior, ChildClass no tiene un método showTest (), por lo que el método showTest () de ParentClass se usa por herencia. Los resultados muestran que dado que el método se está ejecutando en ParentClass, se está evaluando la versión ParentClass de la constante TEST, mientras que debido a que se está evaluando dentro del contexto ChildClass a través de la herencia, se está evaluando la variable de miembro ChildClass $ test.

He leído la documentación, pero parece que no veo ninguna mención de este matiz. ¿Alguien puede arrojarme algo de luz?

Tom Auger
fuente
WTF? ¿¡Anulación constante !? ¡No hagas esto! ¡Nunca!
qwert_ukg
2
@qwert_ukg De hecho. Alguien debería comunicárselo a los desarrolladores de PHP. O al menos permitir final...
Luke Sawczak
1
Seguro que hay casos de uso suficientemente buenos incluso para una anulación constante:]
Arziel

Respuestas:

194

self::No es consciente de la herencia y siempre se refiere a la clase en la que se está ejecutando. Si está utilizando php5.3 +, puede intentarlo static::TESTya que static::es consciente de la herencia.

La diferencia es que static::utiliza "enlace estático tardío". Encuentre más información aquí:

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

Aquí hay un script de prueba simple que escribí:

<?php

class One
{
    const TEST = "test1";

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

$c = new Two();

$c->test();

salida

test2
David Farrell
fuente
22
+ por mencionar static::.
Jason McCreary
Increíble. Gracias por la aclaración y por proporcionar la información adicional sobre enlaces estáticos tardíos (que todavía tengo que digerir).
Tom Auger
3
Dado test()que no es un método estático, ¿por qué no usarlo $this::TESTcon PHP5.3 +?
Xenos
Hola @Xenos: el objetivo del ejemplo era mostrar que el código de nivel de instancia que se ejecutaba en la clase Uno estaba recuperando valores estáticos de la clase Dos. self :: TEST habría devuelto "test1" donde static :: TEST devuelve el "test2" esperado. Espero que ayude, ¡gracias por responder!
David Farrell
Hola @DavidFarrell: Sí, obtuve la diferencia self::/ static::pero no entiendo por qué usar en static::lugar de $this::(no self::). ¿Hay alguna diferencia entre $this::y static::(ya que hay una entre static::/ $this::y self::)?
Xenos
17

En PHP, self se refiere a la clase en la que se define el método o propiedad llamado. Por lo que en su caso está llamando selfen ChildClass, por lo que utiliza la variable de esa clase. Luego usa selfin ParentClass, entonces se referirá a la variable en esa clase.

Si aún desea que la clase secundaria anule la constde la clase principal, ajuste el siguiente código en su clase principal a esto:

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

Tenga en cuenta la staticpalabra clave. Esto utiliza "enlace estático tardío". Ahora su clase principal llamará a la constante de su clase secundaria.

w00
fuente
Pro. estático :: trabajo hecho en abstracción en lugar de uno mismo ::
Błażej Krzakala