16 votes

Pourquoi PHP autorise-t-il les fonctions statiques abstraites

Considérons le code suivant :

abstract class ExampleClass
{
    public static function regularStaticFunction()
    {
        return static::abstractStaticFunction();
    }

    abstract protected static function abstractStaticFunction();
}

ExampleClass::regularStaticFunction();

L'IDE PhpStorm affiche un avertissement sur la déclaration de l'élément abstractStaticFunction qui se lit comme suit :

Normes PHP strictes : La fonction statique 'abstractStaticFunction' ne doit pas être abstraite.

Les fonctions statiques ne doivent pas être abstraites.

Cependant, PHP continue l'exécution du programme lors de l'analyse de cette classe et affiche ce qui suit :

PHP Normes strictes : La fonction statique ExampleClass::abstractStaticFunction() ne doit pas être abstraite dans le code shell php à la ligne 7

Il me semble que, puisque PHP autorise les appels de fonctions statiques sur les classes abstraites, définir une fonction statique abstraite sur une classe abstraite ne devrait pas être possible.

Pourquoi les fonctions statiques abstraites sont-elles autorisées en PHP par l'interpréteur, alors qu'elles n'ont aucun sens ?

36voto

German Lashevich Points 866

C'est une bonne explication de cette réponse par Mark Amery :

Rapport de bogue PHP 53081 a demandé pour que l'avertissement soit supprimé puisque l'ajout de la static::foo() avait rendu les méthodes statiques abstraites raisonnables et utiles. Rasmus Lerdorf (créateur de PHP) commence par qualifier la demande de la demande comme étant bidon et passe par une longue chaîne de mauvais raisonnements pour pour essayer de justifier l'avertissement. Puis, finalement, 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

Exact, 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 bien. Vous ne pouvez évidemment pas appeler self::B(), mais static::B() fonctionne bien.

L'affirmation de Rasmus selon laquelle le code de son exemple "fonctionne bien" est fausse. fausse ; comme vous le savez, il génère un avertissement de mode strict. Je suppose qu'il testait sans que le mode strict soit activé. Quoi qu'il en soit, un Rasmus confus a laissé la demande fermée par erreur comme "bogus".

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 Malheureusement, dans le monde réel, les choix sont parfois le résultat d'erreurs banales mauvais raisonnement plutôt que d'une prise de décision rationnelle. Ceci est simplement une de ces fois.

Heureusement, l'estimable Nikita Popov a supprimé l'avertissement du langage en PHP 7, dans le cadre de l'initiative RFC DE PHP : Reclassifier E_STRICT avis . En fin de compte, Le bon sens l'a emporté, et une fois que PHP 7 sera publié, nous pourrons tous heureusement utiliser abstract static sans recevoir cet avertissement stupide.

13voto

Mark Amery Points 4705

Les fonctions statiques abstraites ne sont pas absurdes ! En fait, elles permettent des conceptions qui sont, à mon sens, plus simples et plus propres que celles auxquelles je devrais recourir dans un langage qui ne les possède pas, comme Java ou C#.

Prenons un exemple. Supposons que j'écrive une application d'entreprise banale qui doit synchroniser certains objets commerciaux entre deux API. Ces API ont des modèles d'objets qui peuvent être mappés les uns aux autres, mais utilisent des noms différents et des formats de sérialisation différents.

En PHP, grâce aux méthodes statiques abstraites, je peux définir une classe de base abstraite pour ces types d'objets métier qui ressemble à ceci...

abstract class ApiObject {
    /** The REST resource URL for this object type in the Foo API. */
    abstract static function fooApiResourceUrl();

    /** The REST resource URL for this object type in the Bar API. */
    abstract static function barApiResourceUrl();

    /** Given an XML response from the Foo API representing an object of this
        type, construct an instance. */
    abstract static function fromFooXml($xml);

    /** Given a JSON response from the Bar API representing an object of this
        type, construct an instance. */
    abstract static function fromBarJson($json);

    /** Serialize this object in the XML format that the Foo API understands */
    abstract function toFooXml();

    /** Serialize this object as JSON that the Bar API understands */
    abstract function toBarJson();
}

... et ensuite chaque sous-classe concrète que je crée sera garanti pour fournir toutes les informations nécessaires pour le récupérer à partir de l'une ou l'autre des deux API et le désérialiser, ou pour le sérialiser et l'envoyer à l'une ou l'autre API. Ensuite, plus tard, je pourrai écrire un code comme celui-ci :

// Ensure that all instances of these types that exist in the Foo API also
// exist in the Bar API:
$classesToSync = ['Widget', 'Frobnicator', 'Lead', 'Invoice'];
foreach ($classesToSync as $apiObjectClass) {
    $fooObjXmls = httpGetRequest($apiObjectClass::fooApiResourceUrl());
    foreach ($fooObjXmls as $fooObjXml) {
        $fooObj = $apiObjectClass::fromFooXml($fooObjXml);
        $json = $fooObj->toBarJson();
        httpPutRequest($apiObjectClass::barApiResourceUrl(), $json);
    }
}

Est-ce que je dois strictement besoin de méthodes statiques abstraites pour écrire le programme ci-dessus ? Non, il y a d'autres modèles que j'aurais pu utiliser, comme avoir chaque classe de modèle associée à une classe de fabrique correspondante qui est responsable de son instanciation à partir de ses représentations JSON ou XML. Mais une telle conception est plus compliquée que celle que j'ai montrée ci-dessus.

La réponse à la question de savoir pourquoi ils sont autorisés, alors, est simplement qu'ils sont utile car ils permettent de réaliser des modèles simples et agréables qui ne seraient pas possibles sans eux. Bien sûr, il y a aussi des arguments contre L'une d'entre elles a été donnée dans la question - qu'il est laid d'exposer des méthodes statiques abstraites sur une classe étant donné que les méthodes statiques sur une classe abstraite sont appelables. Je ne trouve pas ces considérations particulièrement convaincantes, mais même si vous les trouvez, il y a toujours un compromis entre elles et l'utilité que les méthodes statiques abstraites fournissent, et les mainteneurs de PHP ont probablement pesé le pour et le contre en laissant les méthodes statiques abstraites exister.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X