tipos objetos metodos metodo clases abstractas php oop static abstract

objetos - public static function php



¿Por qué PHP 5.2+ no permite métodos abstractos de clase estática? (8)

En php 5.4+ use rasgo:

trait StaticExample { public static function instance () { return new self; } }

y en su clase, al principio:

use StaticExample;

Después de habilitar advertencias estrictas en PHP 5.2, vi una carga de estrictas advertencias de estándares de un proyecto que se escribió originalmente sin advertencias estrictas:

Estándares estrictos : Programa de función estática :: getSelectSQL () no debe ser abstracto en Program.class.inc

La función en cuestión pertenece a un programa de clase padre abstracto y se declara estática abstracta porque debe implementarse en sus clases secundarias, como TVProgram.

Encontré referencias a este cambio here :

Se abandonaron las funciones de clase estática abstracta. Debido a un descuido, PHP 5.0.x y 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?


Es una historia larga y triste.

Cuando PHP 5.2 introdujo por primera vez esta advertencia, los enlaces estáticos tardíos aún no estaban en el idioma. 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 en que podría esperar:

<?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 llamada a self::bar() en foo() se refiere explícitamente al método bar() de ParentClass , incluso cuando se llama a foo() como un 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 fueron inútiles. El objetivo de utilizar un método abstracto es que puede escribir código que llama al método sin saber qué implementación va a realizar, y luego proporcionar diferentes implementaciones en diferentes clases secundarias. Pero dado que PHP 5.2 no ofrece una manera clara de escribir un método de una clase padre que invoque un método estático de la clase hija en la que se llama, este uso de métodos estáticos abstractos no es posible. Por lo tanto, cualquier uso de abstract static en PHP 5.2 es un código incorrecto, probablemente inspirado por un malentendido sobre cómo funciona la palabra clave self . Era completamente razonable lanzar una advertencia sobre esto.

Pero luego apareció PHP 5.3 con la capacidad de referirse a la clase en la que se llamó un método a través de la palabra clave static (a diferencia de la palabra clave self , que siempre se refiere a la clase en la que se definió el método). Si cambia self::bar() a static::bar() en 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 añadida, desapareció el argumento claro de tener una advertencia abstract static . El objetivo principal de los enlaces estáticos finales era permitir que los métodos definidos en una clase padre 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 corregirlo sustituyendo self por static ) está exponiendo un método público ParentClass::foo() que está roto y que realmente no quieres exponer Usar una clase no estática, es decir, hacer que todos los métodos de instancia de métodos y hacer que los hijos de ParentClass sean únicos o algo así resolvería este problema, ya que ParentClass , al ser abstracto, no se puede instanciar y sus métodos de instancia pueden no se llamará Creo que este argumento es débil (porque creo que exponer ParentClass::foo() no es un gran problema y usar singletons en lugar de clases estáticas a menudo es innecesariamente prolijo y feo), pero es posible que estés en desacuerdo, es una llamada un tanto subjetiva.

Entonces, basado en este argumento, los desarrolladores de PHP mantuvieron la advertencia en el idioma, ¿verdad?

Uh, no exactamente .

El informe de error de PHP 53081, vinculado anteriormente, pedía que se descartara la advertencia ya que la adición de la construcción static::foo() 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 atraviesa una larga cadena de malos razonamientos 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 a self :: B (), pero static :: B () está bien.

La afirmación de Rasmus de que el código en su ejemplo "funciona bien" es falso; como usted sabe, arroja una advertencia de modo estricto. Supongo que estaba probando sin el modo estricto encendido. De todos modos, un Rasmus confundido dejó la solicitud erróneamente cerrada 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 en lugar de decisiones racionales. Este es simplemente uno de esos momentos.

Afortunadamente, el estimado Nikita Popov ha eliminado la advertencia del lenguaje en PHP 7 como parte de RFC de PHP: Reclasificar avisos de E_STRICT . En última instancia, la sensatez ha prevalecido, y una vez que se lanza PHP 7 todos podemos felizmente usar abstract static sin recibir esta tonta advertencia.


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ó:

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

Entonces, como un trabajo en torno a usted, podría hacer esto:

<?php abstract class MyFoo implements iMyFoo { public static final function factory($type, $someData) { // don''t forget checking and do whatever else you would // like to do inside a factory method $class = get_called_class()."_".$type; $inst = $class::getInstance($someData); return $inst; } } interface iMyFoo { static function factory($type, $someData); static function getInstance(); function getSomeData(); } ?>

Y ahora haces cumplir que cualquier clase de subclasificación MyFoo implementa un método estático getInstance y un método público getSomeData. Y si no subclasifica MyFoo, puede implementar iMyFoo para crear una clase con funcionalidades similares.


Mire en 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 te digan que evites usar las funciones de lenguaje roto.


No veo ninguna razón para prohibir funciones abstractas estáticas. El mejor argumento de que no hay ninguna 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 PUEDES hacerlo? ¿DEBERÍAMOS HACERLO? - ¿Tienen sentido? Sí. Tiene sentido implementar una parte de una clase y dejar otra parte de una clase al usuario. Tiene sentido en las 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 varias instancias y existen razones para evitarlo, por ejemplo, debe proteger solo una parte de la memoria contra los intrusos. Por lo tanto, tiene mucho sentido implementar una parte del motor y dejar el algoritmo de encriptación al usuario. Este es sólo un ejemplo. Si está acostumbrado a usar funciones estáticas, encontrará muchas más.


Sé que esto es viejo pero ...

¿Por qué no simplemente lanzar una excepción al método estático de la clase primaria? De esa manera, si no lo anula, se produce la excepción.


Yo diría que una clase / interfaz abstracta podría verse como un contrato entre programadores. Se trata más de cómo se ven o se comportan las cosas y no implementa la funcionalidad real. Como se ve en php5.0 y 5.1.x, no es una ley natural lo que impide que los desarrolladores de php lo hagan, sino la necesidad de acompañar otros patrones de diseño de OO en otros idiomas. Básicamente, estas ideas intentan evitar comportamientos inesperados, si uno ya está familiarizado con otros idiomas.


los métodos estáticos pertenecen a la clase que los declaró. Al ampliar la clase, puede crear un método estático del mismo nombre, pero en realidad 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. Ejecutando 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 aún no está permitido en PHP 5.3, http://php.net/lsb está relacionado pero es diferente.