Es una historia larga y triste.
Cuando PHP 5.2 introdujo esta advertencia por primera vez, los enlaces estáticos tardíos aún no estaban en el lenguaje. En caso de que no esté familiarizado con los enlaces estáticos tardíos, tenga en cuenta que un código como este no funciona de la manera esperada:
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
Dejando de lado la advertencia de modo estricto, el código anterior no funciona. La self::bar()
llamada foo()
se refiere explícitamente al bar()
método de ParentClass
, incluso cuando foo()
se llama como método de ChildClass
. Si intenta ejecutar este código con el modo estricto desactivado, verá " Error fatal de PHP: No se puede llamar al método abstracto ParentClass :: bar () ".
Dado esto, los métodos estáticos abstractos en PHP 5.2 eran inútiles. El punto principal de usar un método abstracto es que puede escribir código que llame al método sin saber a qué implementación va a llamar, y luego proporcionar diferentes implementaciones en diferentes clases secundarias. Pero dado que PHP 5.2 no ofrece una forma limpia de escribir un método de una clase primaria que llame a un método estático de la clase secundaria en la que se llama, este uso de métodos estáticos abstractos no es posible. Por lo tanto, cualquier uso de abstract static
PHP 5.2 es un código incorrecto, probablemente inspirado por un malentendido sobre cómo funciona la self
palabra clave. Era completamente razonable lanzar una advertencia sobre esto.
Pero luego llegó PHP 5.3 agregado en la capacidad de referirse a la clase en la que se llamó a un método a través de la static
palabra clave (a diferencia de la self
palabra clave, que siempre se refiere a la clase en la que se definió el método ). Si cambia self::bar()
a static::bar()
mi ejemplo anterior, funciona bien en PHP 5.3 y superior. Puede leer más sobre self
vs static
en New self vs. new static .
Con la palabra clave estática agregada, el argumento claro para haber abstract static
lanzado una advertencia había desaparecido. El objetivo principal de los enlaces estáticos tardíos era permitir que los métodos definidos en una clase primaria llamaran a métodos estáticos que se definirían en clases secundarias; permitir métodos estáticos abstractos parece razonable y consistente dada la existencia de enlaces estáticos tardíos.
Todavía podría, supongo, hacer un caso para mantener la advertencia. Por ejemplo, podría argumentar que dado que PHP le permite llamar a métodos estáticos de clases abstractas, en mi ejemplo anterior (incluso después de arreglarlo reemplazando self
con static
) está exponiendo un método público ParentClass::foo()
que está roto y que realmente no desea exponer. El uso de una clase no estática, es decir, convertir todos los métodos en métodos de instancia y hacer que los hijos de ParentClass
todos sean solteros o algo así, resolvería este problema, ya que ParentClass
, al ser abstracto, no se puede instanciar y, por lo tanto, sus métodos de instancia no pueden ser llamado. Creo que este argumento es débil (porque creo que exponerParentClass::foo()
no es un gran problema y el uso de singletons en lugar de clases estáticas a menudo es innecesariamente detallado y feo), pero es posible que esté razonablemente en desacuerdo: es una llamada algo subjetiva.
Entonces, según este argumento, los desarrolladores de PHP mantuvieron la advertencia en el lenguaje, ¿verdad?
Uh, no exactamente .
El informe de error de PHP 53081, vinculado anteriormente, solicitó que se eliminara la advertencia ya que la adición de la static::foo()
construcción había hecho que los métodos estáticos abstractos fueran razonables y útiles. Rasmus Lerdorf (creador de PHP) comienza etiquetando la solicitud como falsa y pasa por una larga cadena de mal razonamiento para tratar de justificar la advertencia. Entonces, finalmente, este intercambio tiene lugar:
Giorgio
lo sé pero:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
Rasmus
Correcto, así es exactamente como debería funcionar.
Giorgio
pero no está permitido :(
Rasmus
¿Qué no está permitido?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
Esto funciona bien Obviamente no puedes llamar self :: B (), pero static :: B () está bien.
La afirmación de Rasmus de que el código en su ejemplo "funciona bien" es falsa; como saben, arroja una advertencia de modo estricto. Supongo que estaba probando sin el modo estricto activado. En cualquier caso, un confundido Rasmus dejó la solicitud cerrada erróneamente como "falsa".
Y es por eso que la advertencia todavía está en el idioma. Puede que esta no sea una explicación completamente satisfactoria: probablemente haya venido aquí esperando que haya una justificación racional de la advertencia. Desafortunadamente, en el mundo real, a veces las elecciones nacen de errores mundanos y malos razonamientos, más que de la toma racional de decisiones. Este es simplemente uno de esos momentos.
Afortunadamente, la estimable Nikita Popov ha eliminado la advertencia del lenguaje en PHP 7 como parte de PHP RFC: Reclasifique los avisos E_STRICT . En última instancia, la cordura ha prevalecido, y una vez que se lanza PHP 7, todos podemos usarlo felizmente abstract static
sin recibir esta advertencia tonta.