UPDATE : PHP 7.4 unterstützt jetzt Kovarianz und Kontravarianz, wodurch das in dieser Frage aufgeworfene Hauptproblem behoben wird.
Ich bin auf ein Problem mit der Verwendung von Hinweisen zum Rückgabetyp in PHP 7 gestoßen. Mein Verständnis ist, dass Hinweise : self
bedeuten, dass Sie beabsichtigen, dass eine implementierende Klasse sich selbst zurückgibt. Daher habe ich : self
in meinen Schnittstellen darauf hingewiesen, aber als ich versuchte, die Schnittstelle tatsächlich zu implementieren, bekam ich Kompatibilitätsfehler.
Das Folgende ist eine einfache Demonstration des Problems, auf das ich gestoßen bin:
interface iFoo
{
public function bar (string $baz) : self;
}
class Foo implements iFoo
{
public function bar (string $baz) : self
{
echo $baz . PHP_EOL;
return $this;
}
}
(new Foo ()) -> bar ("Fred")
-> bar ("Wilma")
-> bar ("Barney")
-> bar ("Betty");
Die erwartete Ausgabe war:
Fred Wilma Barney Betty
Was ich tatsächlich bekomme ist:
Schwerwiegender PHP-Fehler: Deklaration von Foo :: bar (int $ baz): Foo muss mit iFoo :: bar (int $ baz) kompatibel sein: iFoo in test.php in Zeile 7
Die Sache ist, dass Foo eine Implementierung von iFoo ist, soweit ich das beurteilen kann, sollte die Implementierung perfekt mit der angegebenen Schnittstelle kompatibel sein. Vermutlich könnte ich dieses Problem beheben, indem ich entweder die Schnittstelle oder die implementierende Klasse (oder beide) so ändere, dass ein Hinweis auf die Schnittstelle nach Namen zurückgegeben wird, anstatt sie zu verwendenself
. Mein Verständnis ist jedoch, dass semantisch self
"die Instanz der Klasse zurückgeben, für die Sie gerade die Methode aufgerufen haben" bedeutet ". Eine Änderung an der Schnittstelle würde daher theoretisch bedeuten, dass ich jede Instanz von etwas zurückgeben könnte, die die Schnittstelle implementiert, wenn meine Absicht für die aufgerufene Instanz ist, was zurückgegeben wird.
Ist dies ein Versehen in PHP oder ist dies eine bewusste Designentscheidung? Wenn es das erstere ist, gibt es eine Chance, es in PHP 7.1 behoben zu sehen? Wenn nicht, was ist dann die richtige Art der Rückgabe, die darauf hindeutet, dass Ihre Schnittstelle erwartet, dass Sie die Instanz zurückgeben, für die Sie gerade die Methode zur Verkettung aufgerufen haben?
quelle
self
Rückgabetyp funktionieren soll?self
zu sein, "die Instanz zurückzugeben, auf der Sie dies aufgerufen haben, und nicht irgendeine andere Instanz, die dieselbe Schnittstelle implementiert". Ich scheine mich zu erinnern, dass Java einen ähnlichen Rückgabetyp hatte (obwohl es eine Weile her ist, seit ich Java programmiert habe)Antworten:
self
bezieht sich nicht auf die Instanz, sondern auf die aktuelle Klasse. Es gibt keine Möglichkeit für eine Schnittstelle anzugeben, dass dieselbe Instanz zurückgegeben werden muss.self
Wenn Sie auf die von Ihnen versuchte Weise verwenden, wird nur erzwungen, dass die zurückgegebene Instanz derselben Klasse angehört.Das heißt, Rückgabetypdeklarationen in PHP müssen unveränderlich sein, während das, was Sie versuchen, kovariant ist.
Ihre Verwendung von
self
entspricht:was nicht erlaubt ist.
Der Return Type Declarations RFC hat Folgendes zu sagen :
Zumindest das Beste, was Sie vorerst tun können, ist:
quelle
static
funktioniert, aber er wird nicht einmal erkanntstatic
wird zu PHP 8 hinzugefügt.Es kann auch eine Lösung sein, dass Sie den Rückgabetyp nicht explizit in der Schnittstelle definieren, sondern nur im PHPDoc und dann den bestimmten Rückgabetyp in den Implementierungen definieren:
quelle
Foo
nur zu benutzenself
.Wenn Sie von der Schnittstelle erzwingen möchten, gibt diese Methode ein Objekt zurück, aber der Objekttyp ist nicht der Schnittstellentyp, sondern die Klasse selbst. Dann können Sie es folgendermaßen schreiben:
Es funktioniert seit PHP 7.4.
quelle
Das sieht für mich nach dem erwarteten Verhalten aus.
Ändern Sie einfach Ihre
Foo::bar
Methode, umiFoo
statt zurückzukehren,self
und fertig.Erläuterung:
self
wie in der Schnittstelle verwendet bedeutet "ein Objekt vom TypiFoo
".self
wie in der Implementierung verwendet bedeutet "ein Objekt vom TypFoo
".Daher sind die Rückgabetypen in der Schnittstelle und der Implementierung eindeutig nicht identisch.
In einem der Kommentare wird Java erwähnt und ob Sie dieses Problem haben würden. Die Antwort lautet: Ja, Sie hätten das gleiche Problem, wenn Java Ihnen erlauben würde , solchen Code zu schreiben - was nicht der Fall ist. Da Java erfordert, dass Sie den Namen des Typs anstelle der PHP-
self
Verknüpfung verwenden, werden Sie dies nie wirklich sehen. (Siehe hier für eine Diskussion eines ähnlichen Problems in Java.)quelle
self
ähnlich wie das DeklarierenMyClass::class
?PHP 8 fügt einen "statischen Rückgabetyp" hinzu, der Ihr Problem löst.
Überprüfen Sie diesen RFC: https://wiki.php.net/rfc/static_return_type
quelle