Respuestas:
Definitivamente necesita leer Enlaces estáticos tardíos en el manual de PHP. Sin embargo, intentaré darle un resumen rápido.
Básicamente, se reduce al hecho de que la self
palabra clave no sigue las mismas reglas de herencia. self
siempre se resuelve en la clase en la que se usa. Esto significa que si crea un método en una clase primaria y lo llama desde una clase secundaria, self
no hará referencia al secundario como podría esperar.
El enlace estático tardío introduce un nuevo uso para la static
palabra clave, que aborda esta deficiencia en particular. Cuando lo usa static
, representa la clase donde lo usa por primera vez, es decir. se 'une' a la clase de tiempo de ejecución.
Esos son los dos conceptos básicos detrás de esto. La forma self
, parent
y static
funciona cuando static
está en juego puede ser sutil, por lo que en lugar de ir a más detalle, lo recomiendo encarecidamente que estudie los ejemplos de páginas del manual. Una vez que comprenda los conceptos básicos de cada palabra clave, los ejemplos son bastante necesarios para ver qué tipo de resultados obtendrá.
self
palabra clave no sigue las reglas de herencia. self
siempre se resuelve en la clase en la que se usa". - Lo que no significa que no pueda llamar al método estático de un padre desde un objeto hijo a través de self
, al igual que con los métodos no estáticos. Quizás quieras decir lo correcto, pero deberías reformular eso. Todo realmente importa una vez que los niños hayan nombrado miembros idénticos, ya que puede decidir a qué referirse utilizando en su static::
lugar.
Desde PHP: Enlaces estáticos tardíos - Manual :
A partir de PHP 5.3.0, PHP implementa una característica llamada enlace estático tardío que puede usarse para hacer referencia a la clase llamada en el contexto de herencia estática.
El enlace estático tardío intenta resolver esa limitación mediante la introducción de una palabra clave que hace referencia a la clase que inicialmente se llamó en tiempo de ejecución. ... Se decidió no introducir una nueva palabra clave, sino utilizarla
static
que ya estaba reservada.
Veamos un ejemplo:
<?php
class Car
{
public static function run()
{
return static::getName();
}
private static function getName()
{
return 'Car';
}
}
class Toyota extends Car
{
public static function getName()
{
return 'Toyota';
}
}
echo Car::run(); // Output: Car
echo Toyota::run(); // Output: Toyota
?>
Los enlaces estáticos tardíos funcionan almacenando la clase nombrada en la última "llamada no reenviada". En el caso de llamadas a métodos estáticos, esta es la clase explícitamente nombrada (generalmente la que está a la izquierda del
::
operador); en caso de llamadas a métodos no estáticos, es la clase del objeto. Un "Desvío de llamadas" es una estática que se introduce porself::
,parent::
,static::
, o, si se va para arriba en la jerarquía de clases,forward_static_call()
. La funciónget_called_class()
se puede utilizar para recuperar una cadena con el nombre de la clase llamada estatic::
introduce su alcance.
No hay un comportamiento muy obvio:
El siguiente código produce 'alphabeta'.
class alpha {
function classname(){
return __CLASS__;
}
function selfname(){
return self::classname();
}
function staticname(){
return static::classname();
}
}
class beta extends alpha {
function classname(){
return __CLASS__;
}
}
$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta
Sin embargo, si eliminamos la declaración de la función classname de la clase beta, obtenemos 'alphaalpha' como resultado.
Cito del libro: "PHP Master escribe código de vanguardia".
El enlace estático tardío fue una característica introducida con php 5.3. Nos permite heredar métodos estáticos de una clase primaria y hacer referencia a la clase secundaria que se llama.
Esto significa que puede tener una clase abstracta con métodos estáticos y hacer referencia a las implementaciones concretas de la clase secundaria utilizando la notación static :: method () en lugar del self :: method ().
Siéntase libre de echar un vistazo a la documentación oficial de php también: http://php.net/manual/en/language.oop5.late-static-bindings.php
La forma más clara de explicar el enlace estático tardío es con un ejemplo simple. Eche un vistazo a las dos definiciones de clase a continuación y siga leyendo.
class Vehicle {
public static function invokeDriveByStatic() {
return static::drive(); // Late Static Binding
}
public static function invokeStopBySelf() {
return self::stop(); // NOT Late Static Binding
}
private static function drive(){
return "I'm driving a VEHICLE";
}
private static function stop(){
return "I'm stopping a VEHICLE";
}
}
class Car extends Vehicle {
protected static function drive(){
return "I'm driving a CAR";
}
private static function stop(){
return "I'm stopping a CAR";
}
}
Vemos una clase para padres (vehículo) y una clase para niños (automóvil). La clase para padres tiene 2 métodos públicos:
invokeDriveByStatic
invokeStopBySelf
La clase para padres también tiene 2 métodos privados:
drive
stop
La clase infantil anula 2 métodos:
drive
stop
Ahora invoquemos los métodos públicos:
invokeDriveByStatic
invokeStopBySelf
Pregúntese: ¿Qué clase invoca invokeDriveByStatic
/ invokeStopBySelf
? ¿La clase padre o hijo?
Echa un vistazo a continuación:
// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE
// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR
// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE
La static
palabra clave se utiliza en un patrón de diseño Singleton. Ver enlace: https://refactoring.guru/design-patterns/singleton/php/example
El ejemplo más simple para mostrar la diferencia.
Nota, self :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
Enlace estático tardío, nota estática :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
Mirándolo desde un "¿por qué usaría esto?" perspectiva, es básicamente una forma de cambiar el contexto desde el cual se está interpretando / ejecutando el método estático.
Con self
, el contexto es el que definió el método originalmente. Con static
, es desde el que lo estás llamando.
Además, observe si actualiza las variables estáticas en las clases secundarias. Encontré este resultado (algo) inesperado donde el niño B actualiza al niño C:
class A{
protected static $things;
}
class B extends A {
public static function things(){
static::$things[1] = 'Thing B';
return static::$things;
}
}
class C extends A{
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}
print_r(C::things());
// Array (
// [2] => Thing C
// )
B::things();
print_r(C::things());
// Array (
// [2] => Thing C
// [1] => Thing B
// )
Puede solucionarlo declarando la misma variable en cada clase secundaria, por ejemplo:
class C extends A{
protected static $things; // add this and B will not interfere!
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}