¿Cuál es la diferencia entre self :: $ bar y static :: $ bar en PHP?

125

¿Cuál es la diferencia entre usar selfy staticen el siguiente ejemplo?

class Foo
{
    protected static $bar = 1234;

    public static function instance()
    {
        echo self::$bar;
        echo "\n";
        echo static::$bar;
    }

}

Foo::instance();

produce

1234
1234
cwd
fuente
2
@deceze: Esa es una pregunta similar, pero no es un duplicado. Este pregunta sobre el uso de palabras clave con propiedades, mientras que pregunta sobre cómo usarlas con constructores.
BoltClock

Respuestas:

191

Cuando usa selfpara referirse a un miembro de la clase, se está refiriendo a la clase dentro de la cual usa la palabra clave. En este caso, su Fooclase define una propiedad estática protegida llamada $bar. Cuando usa selfen la Fooclase para hacer referencia a la propiedad, hace referencia a la misma clase.

Por lo tanto, si intentó usar self::$baren otra parte de su Fooclase, pero tenía una Barclase con un valor diferente para la propiedad, usaría en Foo::$barlugar de Bar::$bar, que puede no ser lo que pretende:

class Foo
{
    protected static $bar = 1234;
}

class Bar extends Foo
{
    protected static $bar = 4321;
}

Cuando llamas a un método a través de static, estás invocando una función llamada enlaces estáticos tardíos (introducidos en PHP 5.3).

En el escenario anterior, el uso selfresultará en Foo::$bar(1234). Y el uso staticresultará en Bar::$bar(4321) porque con static, el intérprete tiene en cuenta la redeclaración dentro de la Barclase durante el tiempo de ejecución.

Por lo general, utiliza enlaces estáticos tardíos para métodos o incluso para la propia clase, en lugar de propiedades, ya que no suele volver a declarar propiedades en subclases; un ejemplo del uso de la staticpalabra clave para invocar un constructor de enlace tardío se puede encontrar en esta pregunta relacionada: New self vs new static

Sin embargo, eso no excluye el uso también staticcon propiedades.

BoltClock
fuente
Es muy fácil volver a declarar en la clase secundaria, la clase principal puede ser un valor predeterminado que utiliza la clase secundaria a menos que vuelva a declarar. Si está en la clase principal, supongo que es seguro usar self ::, y si está en una clase secundaria, podría crear un argumento para usar cualquiera de ellos, pero self :: también funcionará si no espera volver a declarar nunca.
Andrew
3
vaya a phpfiddle.org y ejecute esto<?php class Foo { public static $bar = 1234; public static function a( ) { echo 'static'.static::$bar; echo 'self'.self::$bar; } } class Bar extends Foo { public static $bar = 4321; } (new Bar())->a(); ?>
Yevgeniy Afanasyev
2
La redacción de los dos primeros párrafos es confusa, tiene un pronombre ambiguo, "it", y también es redundante, ya que los párrafos posteriores explican la misma información con mayor claridad. Sugiero reemplazar los dos primeros párrafos con el último párrafo que comienza con "En el escenario anterior" en la parte superior. De esa forma, la respuesta básica y directa está en la parte superior. Es claro y fácil de seguir.
ahnbizcad
Otra forma de pensar en esto: self::$abccuando se usa en el interior class Fooes lo mismo que decir Foo::$abc. No se verá afectado por ninguna nueva declaración de $abcen una subclase. AFAIK, la única razón para usar selfes como una abreviatura, para evitar usar el nombre de la clase Foo, que puede ser más largo. [También significa que puede cambiar el nombre de la clase sin cambiar todos esos lugares, pero esa no es una gran razón en mi humilde opinión.] (La elección de nombres de PHP es desafortunada y parece al revés; "estático" es el que puede cambiar, lo cual es opuesto al significado coloquial de la palabra en lenguaje natural "estático".)
ToolmakerSteve
4

Como se mencionó, una de las principales diferencias es que staticpermite enlaces estáticos tardíos. Uno de los escenarios más útiles que encontré fue el de crear clases base para clases Singleton:

class A { // Base Class
    protected static $name = '';
    protected static function getName() {
        return static::$name;
    }
}
class B extends A {
    protected static $name = 'MyCustomNameB';
}
class C extends A {
    protected static $name = 'MyCustomNameC';
}

echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC

El uso return static::$nameen la clase Base devolverá lo que se adjuntó estáticamente cuando se extendió. Si se va a utilizar return self::$namea continuación, B::getName()se devolverá una cadena vacía, ya que es lo que se declaró en la clase base.

ggedde
fuente
0

Con selfllamada:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return self::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "123"
echo (new Bar)->getVar();

Puede ver arriba, aunque hemos anulado el $varcon nuestra Barclase, todavía regresa 123, porque le hemos pedido explícitamente a PHP la selfvariable, que a su vez solicita Foola variable s en su lugar.

Ahora, si intercambiamos la llamada con static, obtendremos Barun valor anulado:

Con staticllamada:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return static::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "234"
echo (new Bar)->getVar();
Steve Bauman
fuente