2016-06-07 6 views
2

Warum sollte der Klassenhinweis mit der Schnittstelle 100% identisch sein?
Ich meine, warum kann nicht akzeptieren, Implementierungsklasse als Typ Hinweis?Typhinweis in Schnittstelle

Um deutlich zu machen,

<?php 
interface MyInterface 
{ 
    public function doMethod(SomeInterface $a) 
    { 
    } 
} 

class MyClass implements MyInterface 
{ 
    public function doMethod(ClassThatImplementsSomeInterface $a) 
    { 
    } 
} 

Fehler: Fatal error: Declaration of MyClass::doMethod() must be compatible with that of MyInterface::doMethod()

Da die Hinting Klasse Typ implementiert SomeInterface erwarte ich, dass sie den Vertrag nicht brechen wird.
Warum will ich es? Wegen der Vorteile der Schnittstellenflexibilität.
Das Gleiche gilt für abstrakte Klasse.
Wenn ich den Code so umschreibe, dass die Methode 'do' keinen Typhinweis hat, weiß ich, dass es 'repariert'.
Aber irgendwie denke ich sollte ich den Vertrag definieren, dass Typ-Hinting $aSomeInterface implementieren muss.
Und, warum verwende ich nicht einfach den gleichen Typhinweis, der SomeInterface ist?
Das ist, weil es Methoden gibt, die in SomeInterface nicht existieren, die ich brauche.
Also, was ist der Sinn dieser Einschränkung?

Reproduzierbare Codepad: http://codepad.org/2PLd8AmV

+1

Ich habe einige Informationen hinzugefügt, gute Frage! – DanFromGermany

+0

Ihre Schnittstelle sagt "Ich werde einen dieser Dank verwenden" und Ihre Implementierung sagt: "Ja, ich benutze stattdessen eine dieser" ... Ich sehe nicht, wo die Frage ist – Dale

Antwort

2

Die Antwort ist einfach, dass Sie Notwendigkeit der Lage sein, auf das Objekt zu verlassen, dass die Schnittstelle erfordert.

echtes Beispiel:

Schnittstelle erfordert APPLE.

Sie versuchen nun, eine Klasse zu implementieren, die I require a GREEN APPLE sagt (es ist immer noch ein Apfel!).

Jemand versucht nun, Ihre INTERFACE zu implementieren und in die Klasse für den grünen Apfel zu legen. Er versucht, eine RED APPLE, die kompatibel ist mit APPLE, aber nicht mit GREEN APPLE.

=> Knall, Vertrag gebrochen!

Coding Beispiel:

interface MyInterface 
{ 
    public function doMethod(SomeInterface $a); 
} 

class MyClass implements MyInterface 
{ 
    public function doMethod(ClassThatImplementsSomeInterface $a) { } 
} 

class DifferentClass implements SomeInterface { } 

$ding = new MyClass(); 
$ding->doMethod(new DifferentClass); 

Dies würde nicht funktionieren, weil DifferentClass nicht ClassThatImplementsSomeInterface ist!

+0

Eigentlich geht es in meinem Fall um Event-Listener. Dies ist das Problem: [http://codepad.org/ZKYUYcid](http://codepad.org/ZKYUYcid) ... Bitte schauen Sie .. Ich bin verwirrt, ob ich die Typhinweis in entfernen sollte die 'handle' Methode in der Listener-Klasse oder ob ich den Typhinweis in der' ChangeUserName' Klasse von 'UserHasLoggedIn' in' Event' umschreiben soll. –

+0

Oder soll ich eine neue Schnittstelle namens 'ChangeUserNameInterface' programmieren, die' Listener' Schnittstelle erweitert und meine 'ChangeUserName' Klasse implementieren lässt? Aber ich denke, es ist zu teuer, da es so viele Event-Listener gibt, was bedeutet, dass es so viele Event-Listener-Interfaces geben wird. Ich bin jetzt verwirrt. –

+0

Sie könnten Schnittstellen und andere Klassen mit abstrakten Klassen kombinieren, aber ich denke, dass Schnittstellen am besten sind (suchen Sie nach "loose couling php", um Erklärungen zu sehen!). – DanFromGermany

1

Typ eine andere Klasse Hinting ändert den Vertrag. Ihre Benutzeroberfläche sagt "alles, was mich implementiert, muss einen bestimmten Typ in dieser Methode verwenden". Ihre tatsächliche Implementierung besagt, dass die Methode tatsächlich einen anderen Typ verwenden muss. Wenn ich ein Objekt habe, das "MyInterface" implementiert, weiß ich, dass es eine do Methode gibt. Ich weiß auch, dass diese Methode ein Argument benötigt, das SomeInterface sein muss. Wegen der Schnittstelle muss ich nicht wirklich irgendwelche Details des Gegenstandes wissen oder interessieren (welche spezifische Implementierung der Schnittstelle, die es ist). Wenn das Objekt, das ich habe, vom Typ MyObject ist, ist das nicht der Fall! Ich brauche eigentlich ein ClassThatImplementsSomeInterface Objekt! Wenn mein Objekt nicht von diesem Typ ist, stürzt mein Programm ab. Möglicherweise zufällig, wenn ich Factory-Methoden habe, die Objekte erstellen. Ich kann nicht mehr darauf vertrauen, dass MyInterface Objekte eine konsistente Implementierung haben und überprüfen müssen, um sicherzustellen, dass das Argument, dass ich es übergeben möchte, das richtige ist.

Das Problem, das Sie haben, ist ein guter Geruch, dass Ihre Klassen und Schnittstellen nicht richtig definiert sind. MyObject ist möglicherweise keine Instanz von SomeInterface. Oder SomeInterface muss eigentlich eine ClassThatImplementsSomeInterface statt nehmen.

Nachtrag

Basierend auf dem Codebeispiel, das Argument von der Griff Funktion entfernen. Haben die __construct Argumente für die spezifischen Typen von Listener Objekte eine bestimmte Implementierung von Event.

interface Event 
{ 
    public function getName(); 
} 

interface Listener 
{ 
    public function handle(); 
} 

class UserHasLoggedIn implements Event 
{ 
    public function __construct($name, $id) 
    { 
     $this->name = $name; 
     $this->id = $id; 
    } 

    public function getName() 
    { 
     return 'UserHasLoggedIn'; 
    } 
} 


class ChangeUserName implements Listener 
{ 
    private $event; 

    public function __construct(UserHasLoggedIn $event) 
    { 
     $this->event = $event; 
    } 

    public function handle() 
    { 

    } 
} 
+0

Dies ist die spezifische Implementierung von es: [http://codepad.org/ZKYUYcid](http://codepad.org/ZKYUYcid) .. Bitte werfen Sie einen Blick darauf .. Was ist Ihr Vorschlag, um mein Problem zu lösen? –

+1

Ich habe meine Antwort mit einem Vorschlag hinzugefügt. Obwohl ich nicht genau weiß, was Sie vorhaben, gibt es nur wenige Ratschläge, die ich Ihnen geben kann. – Schleis

+0

Die Schnittstelle definiert noch keine Verträge für das Ereignis. Was ist, wenn der Parameter __construct kein Event oder Event-abgeleitetes Objekt ist? Ich möchte den Vertrag festlegen –