it-swarm.com.de

PHP Mehrfachvererbung mit Schnittstellen

Ich versuche zu verstehen, wie die Verwendung von Schnittstellen mir mehrfache Vererbung verschafft, während ich gegoogelt habe.

class A
{
 function do1(){}
 function do2(){}
 function do3(){}
}

class B extends A
{
 function do4(){}
 function do5(){}
 function do6(){}
}

class C extends B
{
}

In dem obigen Beispiel verfügt die Klasse C über alle Methoden der Klasse A und B. Die Klasse B verfügt jedoch auch über alle Methoden der Klasse A, was nicht unbedingt erwünscht ist.

Bei meiner Suche wurden Schnittstellen verwendet, um dieses Problem zu lösen, indem Methoden in eine Klasse verschoben und Schnittstellen erstellt werden (siehe unten).

interface A
{
     function do1();
     function do2();
     function do3();
}

interface B
{
     function do4();
     function do5();
     function do6();
}

class C implements A, B
{
     function do1(){}
     function do2(){}
     function do3(){}
     function do4(){}
     function do5(){}
     function do6(){}
}

Ich sehe nicht wirklich, wie das Problem gelöst wird, da der gesamte Code in der neuen Klasse enthalten ist. Wenn ich nur Klasse A wie ursprünglich verwenden wollte, müsste ich eine neue Klasse erstellen, die Schnittstelle A implementiert, und denselben Code in die neue Klasse kopieren.

Fehlt mir etwas?

14
tdbui22

PHP hat keine Mehrfachvererbung. Wenn Sie jedoch PHP 5.4 haben, können Sie traits verwenden, um zumindest zu vermeiden, dass jede Klasse Code kopieren muss.

interface A {
    public function do1();
    public function do2();
    public function do3();
}

trait Alike {
    public function do1() { }
    public function do2() { }
    public function do3() { }
}


interface B {
    public function do4();
    public function do5();
    public function do6();
}

trait Blike {
    public function do4() { }
    public function do5() { }
    public function do6() { }
}


class C implements A, B {
    use Alike, Blike;
}

class D implements A {
    use Alike;

    // You can even "override" methods defined in a trait
    public function do2() { }
}

Beachten Sie jedoch, dass Sie sowohl die Schnittstelle implementieren als auch die Eigenschaft verwenden müssen (oder natürlich Ihre eigene Implementierung bereitstellen). Und C und D sind überhaupt nicht miteinander verbunden, außer bei beiden, die die A-Schnittstelle implementieren. Eigenschaften sind im Grunde nur Kopieren und Einfügen auf Interpreterebene und wirken sich nicht auf die Vererbung aus.

27
cHao

Das erste, was man über Schnittstellen verstehen kann, ist, dass sie NICHT für die Vererbung verwendet werden. Das ist sehr wichtig zu verstehen. Wenn Sie versuchen, mehrere Klassen den gleichen konkreten Code gemeinsam nutzen zu lassen, ist dies nicht das Ziel einer Schnittstelle. 

Die zweite Sache, die Sie verstehen müssen, ist der Unterschied zwischen Clientcode und Servicecode. 

Client-Code ist im Wesentlichen der "letzte Schritt" in einer Folge von Datenanforderungen. Ein Controller oder eine Ansicht in MVC kann als Clientcode betrachtet werden. Das Modell kann mittlerweile als Service-Code betrachtet werden.

Schnittstellen sind für Clientcode vorgesehen, um die Konsistenz der Datentypen zu erzwingen, die er von Diensten erhält. Oder eine andere Möglichkeit, darüber nachzudenken - Schnittstellen sind eine Möglichkeit für Dienste, um sicherzustellen, dass sie mit einer Anforderung von Clientcode kompatibel sind. Das ist alles, was sie tun. Sie stellen buchstäblich eine Schnittstelle bereit, über die auf Daten zugegriffen wird, keine Implementierung, die mehrere Klassen gemeinsam nutzen können.

Um Ihnen ein konkretes Beispiel zu geben:

Client Code - eine ProfileViewController-Klasse für das Benutzerprofil eines Benutzers

class ProfileViewController
{
    public function showProfile(User $user)
    {
         $user->getProfile();
    }
}

Service Code - ein Benutzermodell, das Daten abruft und an den Client-Code weiterleitet, der sie anfordert

class User
{
    public function getProfile()
    {
         $profile = Do some SQL query here or something
         return $profile;
    }
}

Angenommen, Sie entscheiden sich später, Benutzer in Mitglieder, Administratoren, Schiedsrichter, Moderatoren, Verfasser, Bearbeiter usw. aufzuteilen, und dass jeder einen eigenen Profiltyp hat. (z. B. eine eigene benutzerdefinierte Abfrage oder Daten oder was haben Sie?)

Hier gibt es jetzt zwei Probleme:

  1. Sie müssen sicherstellen, dass das, was Sie übergeben, eine getProfile () -Methode enthält. 
  2. showProfile () schlägt fehl, wenn Sie etwas anderes als ein Benutzerobjekt übergeben. 

1 ist durch abstrakte Klassen und Methoden (oder Schnittstellen) leicht zu lösen. 2 klingt zunächst einfach, da Sie Moderatoren, Admins und Members alle zu Unterklassen einer Benutzer-Basisklasse machen können. 

Aber was passiert, wenn Sie auf der Straße neben USER-Profilen auch generische Profile für Dinge erstellen möchten? Vielleicht möchten Sie Profile von Sportlern oder sogar Profile von Prominenten anzeigen. Sie sind keine Benutzer, aber sie haben immer noch Profile/Detailseiten. 

Da sie keine Benutzer sind, macht es möglicherweise keinen Sinn, sie als Unterklassen von User zu betrachten.

Jetzt bist du ein bisschen festgefahren. showProfile () muss mehr als nur ein Benutzerobjekt akzeptieren können. Tatsächlich wissen Sie nicht, welche Art von Objekt Sie letztendlich dort übergeben möchten. Da Sie jedoch immer $ user-> getProfile () packen möchten, müssen alle Elemente, die Sie übergeben, generisch genug sein, um übergeben zu werden, und eine konkrete getProfile () -Methode implementieren. 

Lösung? Schnittstellen !!!!!

Zuerst etwas Servicecode

// First define an interface for ANY service object that will have a profile

interface IHasProfile
{
    public function getProfile();
}


// Next, define the class for an object that should have a profile. I'll do a bunch for the sake of an example...

class User implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique user profile query here
         return $profile;
    }
}


class Celebrity implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique celebrity profile query here
         return $profile;
    }
}


class Car implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique vehicle profile query goes here
         return $profile;
    }
}

Als nächstes den Client-Code, der es verwendet

class ProfileViewController
{
    public function showProfile(IHasProfile $obj)
    {
         $obj->getProfile();
    }
}

Und da hast du es. showProfile () wurde nun so abstrahiert, dass es auf welches -Objekt es egal ist, es kümmert sich nur, dass das Objekt eine öffentliche getProfile () -Methode hat. Sie können also jetzt neue Arten von Objekten nach Herzenslust erstellen, und wenn sie Profile haben sollen, können Sie ihnen einfach "implas IHasProfile" geben, und sie arbeiten automatisch nur mit showProfile (). 

Irgendwie ein erfundenes Beispiel, aber es sollte zumindest das Konzept von Schnittstellen veranschaulichen.

Natürlich könnten Sie einfach nur "faul" sein und das Objekt überhaupt nicht typisieren, sodass ein beliebiges Objekt übergeben werden kann. Aber das ist ein völlig anderes Thema;)

20
AgmLauncher

Mehrfachvererbung ist nur für Interfaces möglich!

wie meine Ausgabe dafür:

php > interface A{};
php > interface B{};
php > interface C extends A,B{};
php > class D implements C{};
php > $d = new D();
php > echo ($d instanceof A);
1
  • Ich habe A- und B-Schnittstellen erstellt und die C-Schnittstelle erweitert sie.
  • Nachdem wir D-Klasse haben, die C-Schnittstelle implementiert
  • Schließlich frage ich, ob $ d object eine Instanz einer Schnittstelle ist. Ja, es stimmt

Für die lulz versuche ich, eine E-Klasse zu erstellen, die die D- und die stdclass-Klasse erweitert und Fehler liefert!

php > class E extends D, stdclass{};
PHP Parse error:  syntax error, unexpected ',', expecting '{' in php Shell code on line 1

Parse error: syntax error, unexpected ',', expecting '{' in php Shell code on line 1
3
tonicospinelli

Mehrfachvererbung ist in PHP nicht möglich, wie in vielen von OOP unterstützten Sprachen 

Siehe ähnliches Thema hier . Das Thema ist in AS3, gibt aber eine Antwort.

Um speziell über das Lösen mit Schnittstellen zu antworten, wird in demselben Beitrag geantwortet: here

Hoffe das hilft

1
Solow Developer

Wie gesagt hier von @tonicospinelli, es scheint, dass in der Tat PHP ermöglicht die mehrfache Vererbung von Schnittstellen , aber es ist nicht klar erklärt, nur ein Beispiel gegeben

Die Art und Weise, wie Mehrfachvererbung funktioniert, PHP übergibt diese mit Traits, das Interfaces implementiert.

Sobald Sie eine Klasse Implementierung einer "Mehrfachschnittstelle" (1) deklariert haben, können Sie bereits definierte Eigenschaften verwenden, um sicherzustellen, dass die Vererbung gut durchgeführt wird.

(1) : Mit "Multi-Interface" meine ich eine Klasse, die ein Interface implementiert, das sich von mehreren anderen Interfaces erstreckt

0
xsubira