Die Deklaration der Methoden sollte mit den übergeordneten Methoden in PHP kompatibel sein

107
Strenge Standards: Die Deklaration von childClass :: customMethod () sollte mit der von parentClass :: customMethod () kompatibel sein.

Was sind mögliche Ursachen für diesen Fehler in PHP? Wo finde ich Informationen darüber, was es bedeutet, kompatibel zu sein ?

waiwai933
quelle
notJim hat es genau richtig. @ waiwai933, wenn Sie die Überschriften (nur die erste Zeile function customMethod( ... )
:)
Weitere Details über die Fehlermeldung und die Auswirkungen auf die PHP-Kompilierungszeit: bugs.php.net/bug.php?id=46851
hakre
1
Mein Problem war, dass ein Argument typisiert wurde, aber ich hatte es nicht use Closure;an die Spitze meiner Klasse gesetzt (da der typisierte Hinweis war Closure). Überprüfen Sie also unbedingt, ob Ihnen solche Abhängigkeiten fehlen.
Ryan

Antworten:

126

childClass::customMethod()hat andere Argumente oder eine andere Zugriffsebene (öffentlich / privat / geschützt) als parentClass::customMethod().

davidtbernal
quelle
1
wahrscheinlich liegt es daran, dass die Sichtbarkeit , Methodensignatur kein Problem in PHP ist
Gabriel Sosa
43
Es ist auch wichtig, die gleichen Standardwerte für das Argument zu haben. Zum Beispiel parentClass::customMethod($thing = false)und childClass::customMethod($thing)würde den Fehler auslösen, da die Methode des Kindes keinen Standardwert für das erste Argument definiert hat.
Charles
1
Ich glaube, Sichtbarkeit ist tatsächlich ein anderer Fehler. Übrigens verwenden wir in meinem Shop aus diesem Grund keinen strengen Modus (wir verwenden E_ALL, IIRC).
Davidtbernal
12
Dies hat sich in PHP 5.4 übrigens geändert: * E_ALL enthält jetzt Fehler auf E_STRICT-Ebene in der Konfigurationsanweisung error_reporting. Siehe hier: php.net/manual/en/migration54.other.php
Duncan Lock
1
Das Fehlen eines kaufmännischen Und ( &) in den Argumenten kann diesen Fehler ebenfalls auslösen.
IvanRF
36

Diese Nachricht bedeutet, dass es bestimmte mögliche Methodenaufrufe gibt, die zur Laufzeit fehlschlagen können. Angenommen, Sie haben

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

Der Compiler vergleicht den Aufruf $ a-> foo () nur mit den Anforderungen von A :: foo (), für die keine Parameter erforderlich sind. $ a kann jedoch ein Objekt der Klasse B sein, für das ein Parameter erforderlich ist, sodass der Aufruf zur Laufzeit fehlschlagen würde.

Dies kann jedoch niemals fehlschlagen und löst den Fehler nicht aus

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

Daher verfügt möglicherweise keine Methode über mehr erforderliche Parameter als die übergeordnete Methode.

Die gleiche Nachricht wird auch generiert, wenn Typhinweise nicht übereinstimmen, aber in diesem Fall ist PHP noch restriktiver. Dies gibt einen Fehler:

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

wie das:

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

Das scheint restriktiver zu sein, als es sein muss, und ich gehe davon aus, dass dies auf Interna zurückzuführen ist.

Sichtbarkeitsunterschiede verursachen einen anderen Fehler, jedoch aus demselben Grund. Keine Methode kann weniger sichtbar sein als die übergeordnete Methode.

ldrut
quelle
2
In Ihrem letzten Beispiel sollte hier kein Fehler auftreten, da stdClass $ a legitimer ist als gemischtes $ a. Gibt es eine Möglichkeit, dies zu umgehen? Ich meine, in diesem Fall sollte PHP dies zulassen, aber es gibt immer noch einen Fehler ...
Galchen
2
Ihr letztes Beispiel ist typsicher, daher ist es sicherlich "restriktiver als es sein muss". Dies kann ein Fall von Fracht-Kult - Programmierung, da es mit Polymorphismus in C ++ und Java in Konflikt en.wikipedia.org/wiki/...
Warbo
Vielen Dank für die Erklärung. In meinem Fall war das erste Beispiel, das Sie gegeben haben, genau das, was meinen Fehler ausgelöst hat.
Billynoah
Vielen Dank dafür, Sir.
Eldoïr
22

Wenn Sie das OOP-Formular beibehalten möchten, ohne einen Fehler auszuschalten, können Sie außerdem:

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
quelle
Ich würde diesen Hack gerne nutzen, um diese Fehler zu umgehen. Ich mache mir Sorgen, dass dieser Ansatz eine Leistungsminderung nach sich ziehen könnte. Ich werde das untersuchen, aber wenn Sie Ressourcen haben, um diese Frage zu beantworten, wäre das großartig.
Adam Friedman
Kommt auf die Situation an, denke ich. Immer noch Ja, es ist vielleicht ein bisschen hackig, aber es ist PHP? schon manchmal kann das eine schöne umgehung sein, danke! <@
Meister James
du hast meinen Tag gerettet! Dies war die einzige Option, um Legacy-PHP5-Projekt auf einem Server mit PHP7 ohne Schmerzen zu starten
Vladkras
In diesem Fall können Sie Standardwerte anstelle von func_get_args(), dh B, verwenden public function foo($a = null, $b = null, $c = null), da dies den von versprochenen Vertrag nicht verletzt A.
Jake
1

Nur um diesen Fehler im Kontext einer Schnittstelle zu erweitern, wenn Sie Ihre Funktionsparameter wie folgt angeben:

Schnittstelle A.

use Bar;

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

Klasse b

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

Wenn Sie vergessen haben, die useAnweisung in Ihre implementierende Klasse (Klasse B) aufzunehmen, wird dieser Fehler auch angezeigt, obwohl die Methodenparameter identisch sind.

Spholt
quelle
0

Ich war mit diesem Problem konfrontiert, als ich versuchte, eine vorhandene Klasse von GitHub aus zu erweitern. Ich werde versuchen, mich selbst zu erklären, indem ich zuerst die Klasse so schreibe, wie ich es mir vorgestellt habe, und dann die Klasse so, wie sie jetzt ist.

Was ich aber

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

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

Was ich endlich getan habe

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

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

Es scheint also, dass dieser Fehler auch auftritt, wenn Sie eine Methode verwenden, die eine Klasse mit Namespace zurückgibt, und Sie versuchen, dieselbe Klasse mit einem anderen Namespace zurückzugeben. Glücklicherweise habe ich diese Lösung gefunden, aber ich verstehe den Nutzen dieser Funktion in PHP 7.2 nicht vollständig. Für mich ist es normal, vorhandene Klassenmethoden nach Bedarf neu zu schreiben, einschließlich der Neudefinition von Eingabeparametern und / oder sogar des Verhaltens der Methode.

Ein Nachteil des vorherigen Ansatzes ist, dass IDEs die neuen Methoden, die in \ mycompany \ CutreApi \ ClassOfVendor () implementiert sind, nicht erkennen konnten. Daher werde ich vorerst mit dieser Implementierung fortfahren.

Derzeit fertig

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

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

Anstatt zu versuchen, die "was auch immer" -Methode zu verwenden, habe ich eine neue mit dem Namen "getWhatever" geschrieben. Tatsächlich machen beide dasselbe und geben nur eine Klasse zurück, aber mit unterschiedlichen Namespaces, wie ich zuvor beschrieben habe.

Hoffe das kann jemandem helfen.

Ferran
quelle