116 votes

La déclaration des méthodes doit être compatible avec les méthodes parentes en PHP

Strict Standards: Declaration of childClass::customMethod() should be compatible with that of parentClass::customMethod()

Quelles sont les causes possibles de cette erreur en PHP ? Où puis-je trouver des informations sur ce que cela signifie d'être compatible ?

0 votes

NotJim a tout à fait raison. @waiwai933, si vous pouviez poster les en-têtes (juste la première ligne : function customMethod( ... ) ) pour chaque fonction nous pourrions vous dire le problème spécifique

0 votes

Plus de détails sur le message d'erreur et les implications au moment de la compilation de PHP : bugs.php.net/bug.php?id=46851

0 votes

130voto

notJim Points 5142

childClass::customMethod() a des arguments différents, ou un niveau d'accès (public/privé/protégé) différent de celui de la commande parentClass::customMethod() .

1 votes

Probablement parce que le visibilité La signature des méthodes n'est pas un problème en PHP.

46 votes

Il est également important d'avoir les mêmes valeurs par défaut pour les arguments. Par exemple, parentClass::customMethod($thing = false) y childClass::customMethod($thing) déclencherait l'erreur, car la méthode de l'enfant n'a pas défini de valeur par défaut pour le premier argument.

1 votes

Je crois que la visibilité est en fait une erreur différente. À propos, dans mon atelier, nous n'utilisons pas le mode strict pour cette raison (nous utilisons E_ALL, IIRC).

38voto

ldrut Points 789

Ce message signifie que certains appels de méthode peuvent échouer lors de l'exécution. Supposons que vous ayez

class A { public function foo($a = 1) {;}}
class B extends A { public function foo($a) {;}}
function bar(A $a) {$a->foo();}

Le compilateur vérifie uniquement l'appel $a->foo() par rapport aux exigences de A::foo() qui ne nécessite aucun paramètre. $a peut cependant être un objet de la classe B qui nécessite un paramètre et donc l'appel échouerait à l'exécution.

Ceci ne peut cependant jamais échouer et ne déclenche pas l'erreur

class A { public function foo($a) {;}}
class B extends A { public function foo($a = 1) {;}}
function bar(A $a) {$a->foo();}

Ainsi, aucune méthode ne peut avoir plus de paramètres requis que sa méthode parente.

Le même message est également généré lorsque les indices de type ne correspondent pas, mais dans ce cas, PHP est encore plus restrictif. Cela donne une erreur :

class A { public function foo(StdClass $a) {;}}
class B extends A { public function foo($a) {;}}

tout comme ceci :

class A { public function foo($a) {;}}
class B extends A { public function foo(StdClass $a) {;}}

Cela semble plus restrictif que nécessaire et je suppose que c'est dû aux internes.

Les différences de visibilité provoquent une erreur différente, mais pour la même raison fondamentale. Aucune méthode ne peut être moins visible que sa méthode parente.

3 votes

Dans votre dernier exemple - il ne devrait pas y avoir d'erreur ici parce que c'est légitime, stdClass $a est plus restrictif que mixed $a. y a-t-il un moyen de contourner cela ? je veux dire que dans ce cas, PHP devrait l'autoriser mais il donne quand même une erreur...

2 votes

Votre dernier exemple est sûr du point de vue du type, il est donc certainement "plus restrictif qu'il ne doit l'être". Il s'agit peut-être d'un cas de programmation de type "cargo-cult", puisqu'il entre en conflit avec le polymorphisme en C++ et Java. fr.wikipedia.org/wiki/

0 votes

Merci pour l'explication, dans mon cas le premier exemple que vous avez donné était exactement ce qui déclenchait mon erreur.

24voto

Sajjad Shirazy Points 1213

Si vous voulez garder la forme OOP sans désactiver aucune erreur, vous pouvez aussi le faire :

class A
{
    public function foo() {
        ;
    }
}
class B extends A
{
    /*instead of : 
    public function foo($a, $b, $c) {*/
    public function foo() {
        list($a, $b, $c) = func_get_args();
        // ...

    }
}

2voto

Spholt Points 742

Pour développer cette erreur dans le contexte d'une interface, si vous indiquez les paramètres de votre fonction de la manière suivante :

interface A

use Bar;

interface A
{
    public function foo(Bar $b);
}

Classe B

class B implements A
{
    public function foo(Bar $b);
}

Si vous avez oublié d'inclure le use sur votre classe d'implémentation (classe B), vous obtiendrez également cette erreur, même si les paramètres de la méthode sont identiques.

0voto

Ferran Points 74

J'ai rencontré ce problème en essayant d'étendre une classe existante de GitHub. Je vais essayer de m'expliquer, en écrivant d'abord la classe telle que je pensais qu'elle devait être, puis la classe telle qu'elle est maintenant.

Ce que j'ai pensé

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Ce que j'ai finalement fait

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new \mycompany\CutreApi\ClassOfVendor();
   }
}

Il semble donc que cette erreur se produise également lorsque vous utilisez une méthode qui renvoie une classe avec un espace de nom, et que vous essayez de renvoyer la même classe mais avec un autre espace de nom. Heureusement j'ai trouvé cette solution, mais je ne comprends pas bien l'intérêt de cette fonctionnalité dans php 7.2, pour moi il est normal de réécrire les méthodes de classes existantes selon vos besoins, y compris la redéfinition des paramètres d'entrée et/ou même le comportement de la méthode.

L'un des inconvénients de l'approche précédente est que les IDE ne pouvaient pas reconnaître les nouvelles méthodes mises en œuvre dans le module \mycompany\CutreApi\ClassOfVendor (). Donc, pour l'instant, je vais me contenter de cette implémentation.

Actuellement fait

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function getWhatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Donc, au lieu d'essayer d'utiliser la méthode "whatever", j'en ai écrit une nouvelle appelée "getWhatever". En fait, les deux font la même chose, en retournant une classe, mais avec des espaces de noms différents, comme je l'ai décrit précédemment.

J'espère que cela pourra aider quelqu'un.

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