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

107
Normes strictes: La déclaration de childClass :: customMethod () doit être compatible avec celle de parentClass :: customMethod ()

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

waiwai933
la source
notJim a tout à fait raison. @ waiwai933, si vous pouviez publier les en-têtes (juste la première ligne function customMethod( ... )
:)
Plus de détails sur le message d'erreur et les implications de la compilation PHP: bugs.php.net/bug.php?id=46851
hakre
1
Mon problème était qu'un argument était une use Closure;indication de type, mais je n'avais pas ajouté au début de ma classe (puisque l'indice de type l'était Closure). Alors ... assurez-vous de vérifier si vous manquez de telles dépendances.
Ryan

Réponses:

126

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

davidtbernal
la source
1
c'est probablement parce que la visibilité , la signature des méthodes n'est pas un problème en PHP
Gabriel Sosa
43
Il est également important d'avoir les mêmes valeurs par défaut d'argument exact. Par exemple, parentClass::customMethod($thing = false)et 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.
Charles
1
Je pense que la visibilité est en fait une erreur différente. Au fait, dans ma boutique, nous n'utilisons pas le mode strict, à cause de cela (nous utilisons E_ALL, IIRC).
davidtbernal
12
Cela a changé dans PHP 5.4, btw: * E_ALL inclut désormais les erreurs de niveau E_STRICT dans la directive de configuration error_reporting. Voir ici: php.net/manual/en/migration54.other.php
Duncan Lock
1
L'absence d'une esperluette ( &) dans les arguments peut également déclencher cette erreur.
IvanRF
36

Ce message signifie qu'il existe certains appels de méthode possibles qui peuvent échouer au moment 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 classe B qui nécessite un paramètre et donc l'appel échouerait à l'exécution.

Cela 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();}

Aucune méthode ne peut donc 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) {;}}

comme ça:

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 cela est dû à des éléments 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.

ldrut
la source
2
dans votre dernier exemple - il ne devrait pas y avoir d'erreur ici car c'est légitime, stdClass $ a est plus restrictif que mixed $ a. Y a-t-il un moyen de contourner ceci? je veux dire dans ce cas PHP devrait permettre cela mais il donne toujours une erreur ...
galchen
2
Votre dernier exemple est de type sécurisé, il est donc certainement "plus restrictif que nécessaire". Cela peut être un cas de programmation culte de la cargaison, car il entre en conflit avec le polymorphisme en C ++ et Java en.wikipedia.org/wiki/…
Warbo
merci pour l'explication, dans mon cas le premier exemple que vous avez donné était exactement ce qui déclenchait mon erreur.
billynoah
Merci pour cela, monsieur.
Eldoïr
22

si vous souhaitez conserver le formulaire POO sans désactiver aucune erreur, vous pouvez également:

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();
        // ...

    }
}
Sajjad Shirazy
la source
J'adorerais utiliser ce hack pour contourner ces erreurs. Je crains qu'il puisse y avoir une pénalité de performance à cette approche? Je vais rechercher ceci, mais si vous avez des ressources pour aider à répondre à cette question, ce serait génial.
Adam Friedman
Cela dépend de la situation, je suppose. Toujours oui c'est peut-être un peu hacky, mais c'est php? déjà, parfois cela peut être un bon travail, merci! <@
Master James
tu as sauvé ma journée! c'était la seule option pour lancer un projet php5 hérité sur un serveur avec php7 sans douleur
vladkras
Pour ce cas , vous pouvez utiliser des valeurs par défaut au lieu de func_get_args(), par exemple, en B, public function foo($a = null, $b = null, $c = null)car cela ne rompt pas le contrat promis par A.
Jake
1

Juste pour développer cette erreur dans le contexte d'une interface, si vous tapez une indication de vos paramètres de fonction comme ceci:

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 l' useinstruction 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.

Spholt
la source
0

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

Ce que je pensais

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 déclenche également lorsque vous utilisez une méthode qui retourne une classe d'espacement de noms et que vous essayez de renvoyer la même classe mais avec un autre espace de noms. Heureusement j'ai trouvé cette solution, mais je ne comprends pas tout à fait l'intérêt de cette fonctionnalité en php 7.2, pour moi il est normal de réécrire les méthodes de classe existantes au fur et à mesure que vous en avez besoin, y compris la redéfinition des paramètres d'entrée et / ou même le comportement du méthode.

Un inconvénient de l'approche précédente est que les IDE ne pouvaient pas reconnaître les nouvelles méthodes implémentées dans \ mycompany \ CutreApi \ ClassOfVendor (). Donc, pour l'instant, je vais aller avec 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 "n'importe quoi", j'en ai écrit une nouvelle appelée "getWwhat". En fait, les deux font la même chose, renvoyant simplement une classe, mais avec différents espaces de noms comme je l'ai décrit précédemment.

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

Ferran
la source