Después de habilitar advertencias estrictas en PHP 5.2, vi una carga de advertencias de estándares estrictos de un proyecto que se escribió originalmente sin advertencias estrictas:
Estándares estrictos : Función estática Program :: getSelectSQL () no debe ser abstracto en Program.class.inc
La función en cuestión pertenece a un programa de clase primaria abstracta y se declara estática abstracta porque debe implementarse en sus clases secundarias, como TVProgram.
Encontré referencias a este cambio aquí :
Funciones de clase estáticas abstractas descartadas. Debido a un descuido, PHP 5.0.xy 5.1.x permitieron funciones estáticas abstractas en las clases. A partir de PHP 5.2.x, solo las interfaces pueden tenerlos.
Mi pregunta es: ¿alguien puede explicar de manera clara por qué no debería haber una función estática abstracta en PHP?
Respuestas:
Los métodos estáticos pertenecen a la clase que los declaró. Al extender la clase, puede crear un método estático con el mismo nombre, pero de hecho no está implementando un método abstracto estático.
Lo mismo aplica para extender cualquier clase con métodos estáticos. Si extiende esa clase y crea un método estático de la misma firma, en realidad no está anulando el método estático de la superclase
EDITAR (16 de septiembre de 2009)
Actualización sobre esto. Al ejecutar PHP 5.3, veo que la estática abstracta está de vuelta, para bien o para mal. (ver http://php.net/lsb para más información)
CORRECCIÓN (por philfreo)
abstract static
todavía no está permitido en PHP 5.3, LSB está relacionado pero es diferente.fuente
abstract static
puede ser útil en este caso.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:
Dejando de lado la advertencia de modo estricto, el código anterior no funciona. La
self::bar()
llamadafoo()
se refiere explícitamente albar()
método deParentClass
, incluso cuandofoo()
se llama como método deChildClass
. 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 laself
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 laself
palabra clave, que siempre se refiere a la clase en la que se definió el método ). Si cambiaself::bar()
astatic::bar()
mi ejemplo anterior, funciona bien en PHP 5.3 y superior. Puede leer más sobreself
vsstatic
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
constatic
) está exponiendo un método públicoParentClass::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 deParentClass
todos sean solteros o algo así, resolvería este problema, ya queParentClass
, 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: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.fuente
Hay una solución muy simple para este problema, que en realidad tiene sentido desde el punto de vista del diseño. Como Jonathan escribió:
Entonces, como una solución alternativa, podría hacer esto:
Y ahora hace cumplir que cualquier clase que subclasifique MyFoo implemente un método estático getInstance y un método getSomeData público. Y si no subclasifica MyFoo, aún puede implementar iMyFoo para crear una clase con una funcionalidad similar.
fuente
static::
pueden ser útiles.abstract static
métodos, sin PHP bitching ...Sé que esto es viejo pero ...
¿Por qué no simplemente lanzar una excepción al método estático de esa clase padre, de esa manera, si no lo anula, se produce la excepción?
fuente
Yo diría que una clase / interfaz abstracta podría verse como un contrato entre programadores. Trata más sobre cómo deberían verse / comportarse las cosas y no implementar la funcionalidad real. Como se ve en php5.0 y 5.1.x, no es una ley natural que impida que los desarrolladores de php lo hagan, sino la necesidad de seguir otros patrones de diseño OO en otros idiomas. Básicamente, estas ideas intentan evitar comportamientos inesperados, si uno ya está familiarizado con otros idiomas.
fuente
No veo ninguna razón para prohibir las funciones abstractas estáticas. El mejor argumento de que no hay razón para prohibirlos es que están permitidos en Java. Las preguntas son: - ¿Son técnicamente factibles? - Sí, ya que existía en PHP 5.2 y existen en Java. Entonces, ¿cuándo PUEDE hacerlo? ¿DEBEMOS hacerlo? - ¿Tienen sentido? Si. Tiene sentido implementar una parte de una clase y dejar otra parte de una clase al usuario. Tiene sentido en funciones no estáticas, ¿por qué no debería tener sentido para las funciones estáticas? Un uso de las funciones estáticas son las clases donde no debe haber más de una instancia (singletons). Por ejemplo, un motor de cifrado. No es necesario que exista en varios casos y existen razones para evitarlo; por ejemplo, debe proteger solo una parte de la memoria contra intrusos. Por lo tanto, tiene mucho sentido implementar una parte del motor y dejar el algoritmo de cifrado al usuario. Este es sólo un ejemplo. Si está acostumbrado a usar funciones estáticas, encontrará muchas más.
fuente
En php 5.4+ use rasgo:
y en tu clase pon al principio:
fuente
abstract public static function get_table_name();
un rasgo y usar ese rasgo dentro de mi clase abstracta sin más advertencias E_STRICT! Esto todavía impuso la definición del método estático en los niños como esperaba. ¡Fantástico!Examine los problemas de 'Enlace estático tardío' de PHP. Si está poniendo métodos estáticos en clases abstractas, probablemente lo encontrará más pronto que tarde. Tiene sentido que las advertencias estrictas le indiquen que evite usar funciones de lenguaje roto.
fuente