C'est une histoire longue et triste.
Lorsque PHP 5.2 a introduit cet avertissement pour la première fois, les liaisons statiques tardives n'étaient pas encore dans le langage. Si vous n'êtes pas familier avec les liaisons statiques tardives, notez qu'un code comme celui-ci ne fonctionne pas comme prévu:
<?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();
Laissant de côté l'avertissement de mode strict, le code ci-dessus ne fonctionne pas. L' self::bar()
appel en foo()
fait explicitement référence à la bar()
méthode de ParentClass
, même lorsqu'elle foo()
est appelée en tant que méthode de ChildClass
. Si vous essayez d'exécuter ce code avec le mode strict désactivé, vous verrez " Erreur fatale PHP: impossible d'appeler la méthode abstraite ParentClass :: bar () ".
Compte tenu de cela, les méthodes statiques abstraites de PHP 5.2 étaient inutiles. L' intérêt d'utiliser une méthode abstraite est que vous pouvez écrire du code qui appelle la méthode sans savoir quelle implémentation elle va appeler - puis fournir différentes implémentations sur différentes classes enfants. Mais puisque PHP 5.2 n'offre aucun moyen propre d'écrire une méthode d'une classe parente qui appelle une méthode statique de la classe enfant sur laquelle elle est appelée, cette utilisation de méthodes statiques abstraites n'est pas possible. Par conséquent, toute utilisation de abstract static
PHP 5.2 est un mauvais code, probablement inspiré par une mauvaise compréhension du fonctionnement du self
mot clé. Il était tout à fait raisonnable de jeter un avertissement à ce sujet.
Mais ensuite PHP 5.3 est venu ajouté dans la possibilité de faire référence à la classe sur laquelle une méthode a été appelée via le static
mot - clé (contrairement au self
mot - clé, qui fait toujours référence à la classe dans laquelle la méthode a été définie ). Si vous passez self::bar()
à static::bar()
dans mon exemple ci-dessus, cela fonctionne bien dans PHP 5.3 et supérieur. Vous pouvez en savoir plus sur self
vs static
à New self vs new static .
Avec le mot clé static ajouté, l'argument clair pour avoir abstract static
lancé un avertissement avait disparu. Le but principal des liaisons statiques tardives était de permettre aux méthodes définies dans une classe parente d'appeler des méthodes statiques qui seraient définies dans des classes enfants; autoriser des méthodes statiques abstraites semble raisonnable et cohérente étant donné l'existence de liaisons statiques tardives.
Vous pourriez encore, je suppose, plaider pour le maintien de l'avertissement. Par exemple, vous pourriez soutenir que puisque PHP vous permet d'appeler des méthodes statiques de classes abstraites, dans mon exemple ci-dessus (même après l'avoir corrigé en le remplaçant self
par static
) vous exposez une méthode publique ParentClass::foo()
qui est cassée et que vous ne voulez pas vraiment exposer. Utiliser une classe non statique - c'est-à-dire faire de toutes les méthodes des méthodes d'instance et faire des enfants de ParentClass
tous des singletons ou quelque chose - résoudrait ce problème, car ParentClass
étant abstrait, ne peut pas être instancié et donc ses méthodes d'instance ne peuvent pas être appelé. Je pense que cet argument est faible (car je pense qu'exposerParentClass::foo()
n'est pas un gros problème et utiliser des singletons au lieu de classes statiques est souvent inutilement verbeux et laid), mais vous pourriez raisonnablement être en désaccord - c'est un appel quelque peu subjectif.
Donc, sur la base de cet argument, les développeurs PHP ont gardé l'avertissement dans le langage, non?
Euh, pas exactement .
Le rapport de bogue PHP 53081, lié ci-dessus, demandait que l'avertissement soit supprimé car l'ajout de la static::foo()
construction avait rendu les méthodes statiques abstraites raisonnables et utiles. Rasmus Lerdorf (créateur de PHP) commence par qualifier la demande de fausse et passe par une longue chaîne de mauvais raisonnement pour essayer de justifier l'avertissement. Puis, enfin, cet échange a lieu:
Giorgio
je sais, mais:
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
Bon, c'est exactement comme ça que ça devrait fonctionner.
Giorgio
mais ce n'est pas autorisé :(
Rasmus
Qu'est-ce qui n'est pas autorisé?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
Cela fonctionne très bien. Vous ne pouvez évidemment pas appeler self :: B (), mais static :: B () est bien.
L'affirmation de Rasmus selon laquelle le code de son exemple "fonctionne bien" est fausse; comme vous le savez, il lance un avertissement de mode strict. Je suppose qu'il testait sans le mode strict activé. Quoi qu'il en soit, un Rasmus confus a laissé la demande fermée à tort comme "bidon".
Et c'est pourquoi l'avertissement est toujours dans la langue. Ce n'est peut-être pas une explication entièrement satisfaisante - vous êtes probablement venu ici en espérant qu'il y avait une justification rationnelle de l'avertissement. Malheureusement, dans le monde réel, les choix naissent parfois d'erreurs banales et de mauvais raisonnements plutôt que d'une prise de décision rationnelle. C'est simplement l'un de ces moments.
Heureusement, l'estimable Nikita Popov a supprimé l'avertissement du langage en PHP 7 dans le cadre des notifications PHP RFC: Reclassify E_STRICT . En fin de compte, la raison a prévalu, et une fois que PHP 7 est sorti, nous pouvons tous l'utiliser avec plaisir abstract static
sans recevoir cet avertissement stupide.