Können Sie überschreiben von interface-Methoden mit unterschiedlichen, aber "kompatibel", Signaturen?
Betrachten Sie die folgende PHP-Schnittstellen:
interface Item {
//some methods here
}
interface SuperItem extends Item {
//some extra methods here, not defined in Item
}
interface Collection {
public function add(Item $item);
//more methods here
}
interface SuperCollection extends Collection {
public function add(SuperItem $item);
//more methods here that "override" the Collection methods like "add()" does
}
Bin ich mit PHPStorm, und wenn ich dies mache, bekomme ich eine Fehlermeldung in der IDE, die im wesentlichen besagt die definition für add()
im SuperCollection
ist nicht kompatibel mit der definition der Schnittstelle erstreckt, Collection
.
In einer Weise, die ich sehen kann, dass dies ein problem, da die Signatur der Methode nicht übereinstimmen, die es "überschreibt" genau. Ich habe aber das Gefühl, dass diese kompatibel sein würde, als SuperItem
erstreckt Item
, so würde ich schauen add(SuperItem)
das gleiche wie add(Item)
.
Ich bin neugierig, wenn dies unterstützt wird, die von PHP (version 5.4 oder höher), und vielleicht ist das IDE hat einen bug, der nicht richtig fangen.
- In 5.3, bekomme ich "Fatal error: Declaration of SuperCollection::add() muss kompatibel mit der Sammlung::add()". So wie es aussieht PhpStorm ist richtig. Was glaubst du, warum 5.4 könnte sich anders Verhalten?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nein, ich bin mir ziemlich sicher, dass PHP nicht unterstützt diese, in jeder version, und es würde nicht zu besiegen den Punkt der Schnittstelle.
Der Sinn einer Schnittstelle ist, dass es gibt Ihnen einen festen Vertrag mit anderen Codes, die auf die gleiche Schnittstelle.
Betrachten wir zum Beispiel eine Funktion wie diese:
Diese Funktion erwartet ein Objekt implementiert, dass das
Collection
- Schnittstelle.Innerhalb der Funktion, die der Programmierer in der Lage sein würde zu schreiben, Aufrufe von Methoden definiert sind, die in
Collection
im wissen, dass das Objekt würde bei der Umsetzung dieser Methoden.Wenn Sie eine überschriebene Schnittstelle wie dieser, dann haben Sie ein problem mit diesem, weil ein
SuperCollection
Objekt konnte an die Funktion übergeben. Es würde funktionieren, weil es auch einCollection
Objekt durch die Vererbung. Aber dann wird der code in der Funktion sich nicht mehr sicher, dass er weiß, was die definition deradd()
Methode ist.Eine Schnittstelle ist, durch definition, einen festen Vertrag. Es ist unveränderlich.
Als alternative, könntest du überlegen, mit abstrakten Klassen statt interfaces. Dies würde es ermöglichen, Sie zu überschreiben, die im nicht-Strict-Modus, obwohl Sie noch Fehler erhalten, wenn Sie den Strikten Modus, für den gleichen Gründen.
add()
ing ein Element bedeutet, Sie können auchdelete()
es). Ihre einzige Aufgabe ist es, die Durchsetzung kompatibel Methodensignaturen (Eingänge/Ausgänge). Sie sind richtig über Sie zu Feste Verträge, aber falsch über den Sinn und Zweck des Vertrages. Zwei Klassen könnte sehr leicht implementieren die gleiche Schnittstelle und ganz anders Semantik (z.B.add()
könnte tatsächlich löschen Elemente, die in einer Klasse, und es wäre kein Problem, solange die ein - /Ausgänge bleibt der gleiche Typ).Als workaround bin ich mit PHPDoc-Blöcke-in-Schnittstellen.
So, in Fall, dass Sie ordnungsgemäß Verwendung von Schnittstellen IDE sollte es Ihnen helfen, fangen einige Fehler. Sie können ähnliche Technik überschreiben Rückgabewert-Typen sowie.
Können Sie nicht ändern, die Methoden-Argumente.
http://php.net/manual/en/language.oop5.interfaces.php
Ausweitung interface nicht ändern darf methodendefinitionen. Wenn Ihr SuperItem ist die Erweiterung Artikel, es sollte der Durchreise-Klassen Implementierung der Collection-Schnittstelle ohne Probleme.
Aber basierend auf dem, was Sie wirklich wollen, zu tun, die Sie ausprobieren können:
Erstellung einer Schnittstelle mit leicht unterschiedlichen Methoden für die SuperItem und umzusetzen, dass:
Verwenden Dekorator-Muster zu erstellen, die fast die gleiche Schnittstelle ohne Verlängerung:
Dann decorator (abstrakte) Klasse, die diese Schnittstelle nutzen:
Wird die Antwort später ändern diese Jahr (2019), wenn PHP 7.4 freigegeben wird, wie geplant, mit verbesserte Art Varianz.
Den code aus der Frage, die bleibt, ungültig:
Weil die
Collection
- Schnittstelle garantiert, dass alles, was, die es akzeptieren kann ein beliebiges Objekt vom TypItem
als parameter deradd
.Jedoch der folgende code gültig sein wird in PHP 7.4:
In diesem Fall
Collection
garantiert, dass es kann akzeptierenSuperItem
. Da alleSuperItem
s sindItem
sSuperCollection
macht auch diese Garantie, während auch die Gewährleistung, dass es kann akzeptieren, jede andere Art vonItem
. Dies ist bekannt als ein Kontravariant parameter der Methode geben.Gibt es eine eingeschränkte form des Typ Abweichung in aktuellen PHP-Versionen. Vorausgesetzt, andere Schnittstellen sind als in der Frage, die
SuperCollection
können definiert werden als:Dies kann interpretiert werden als Bedeutung einen beliebigen Wert überhaupt weitergegeben werden dürfen, um die
add
Methode. Der Kurs umfasst alleItem
s, so ist dies immer noch sicher ist, oder es kann interpretiert werden, dass eine unbestimmte Klasse von Werten, die in der Regel dokumentiertmixed
weitergegeben werden können und der Programmierer braucht, der die anderen wissen genau, welche arbeiten können mit der Funktion.Das problem ist nicht die IDE. In PHP können Sie eine Methode überschreiben. Und die Kompatibilität ist nur in die entgegengesetzte Richtung - Sie können sicher erwarten, dass eine Instanz der übergeordneten Klasse und erhalten eine Unterklasse. Aber wenn Sie erwarten, dass eine Unterklasse ist, können Sie nicht sicher sein, falls Sie erhalten, die übergeordnete Klasse, die Unterklasse kann Methoden definieren, die nicht in der übergeordneten. Aber noch können Sie nicht überschreiben die Methode
Wenn ich eine Methode, die ich brauchen kann, um eine überlastung (die PHP nicht unterstützt), ich stellen Sie sicher, dass eine Methode, Argumente (in der Regel der Letzte) ist ein array. Auf diese Weise kann ich weitergeben, was ich brauche. Dann kann ich das testen innerhalb der Funktion für verschiedene array-Elemente, um mir zu sagen, was routine in der Methode, die ich brauchen, um in der Regel in einer select/case.