WernerK: Sinn Interfaces?

Hallo,
ich versuche gerade ein wenig mehr in PHP OOP einzutauchen.
So richtig erschliesst sich mir der Sinn von Interfaces noch nicht.

ich habe hier ein Beispiel gefunden:
http://www.rither.de/a/informatik/php-beispiele/klassen/ein-einfaches-interface/

Jetzt könnte man doch aber das Ganze auch einfach so schreiben:
Also ganz ohne interface.

  
   class Hund {  
        private $name;  
  
        public function __construct($name) {  
            $this->name = $name;  
        }  
  
        public function getName() {  
            return $this->name;  
        }  
    }  
  
  
  
    class VirtuelleKatze {  
        private $name;  
  
        public function __construct() {  
            $names = array('Tigger', 'CyberKatze', 'Mauzer', 'Mausejäger');  
            shuffle($names);  
            $this->name = array_pop($names);  
        }  
  
        public function getName() {  
            return $this->name;  
        }  
    }  
  
  
    $einHund = new Hund('Rex');  
    $vKatze = new VirtuelleKatze();  
    var_dump($einHund->getName());  
    var_dump($vKatze->getName());  

Was bringt einem das Interface wenn man doch jedes mal in der Klasse die Funktion "getName" aufrufen muss? Dann kann man es doch gleich so machen wie in meiner Version ?

vielen Dank für eine Erklärung
Gruss
Werner

  1. Tach!

    So richtig erschliesst sich mir der Sinn von Interfaces noch nicht.

    Ein Interface ist eine Art Versicherung/Vertrag, dass die Klasse, die das Interface implementiert, alle Mitglieder des Interfaces implementiert hat.

    Jetzt könnte man doch aber das Ganze auch einfach so schreiben:
    Also ganz ohne interface.

    Ja, aber dann kannst du eine Vogel-Klasse ohne getName() erstellen und Code, der sich auf diese Methode verlässt, greift ins Leere. Zusammen mit Type Hinting kannst du bei einem Parameter einer Funktion/Methode sicherstellen, dass nur Klassen mit einer solchen Methode übergeben werden können.

    Was bringt einem das Interface wenn man doch jedes mal in der Klasse die Funktion "getName" aufrufen muss?

    Wieso "aufrufen muss"? Meinst du vielleicht, dass man die Methode erstellen muss? Dann, siehe oben. Das Interface ist nur der Vertrag auf einem Blatt Papier. Die Leistung erbringen muss eine konkrete Klasse.

    dedlfix.

    1. Hallo,

      danke an alle für die Erklärung.

      Ein Interface ist eine Art Versicherung/Vertrag, dass die Klasse, die das Interface implementiert, alle Mitglieder des Interfaces implementiert hat.

      hm. ok. Um nochmals bei dem Beispiel von mir zu bleiben.

        
      interface IHaustier {  
       // Die Methode wird über das Interface nur vorgeschrieben,  
       // daher darf sie keinen Inhalt haben.  
       public function getName();  
      }
      

      Die Funktion "getName()" im Interface macht ja erst mal nichts.

      Die Klasse Hund unten nutzt das Interface IHaustier. Aber trotzdem muss man nochmals dieselbe Funktion in der Klasse aufführen bzw. schreiben.

        
      class Hund implements IHaustier {  
              private $name;  
        
              public function __construct($name) {  
                  $this->name = $name;  
              }  
        
              // Die vom Interface IHaustier verlangte Methode  
              public function getName() {  
                  return $this->name;  
              }  
          }  
      
      

      Mehr Sinn würde es für mich machen, wenn die Funktion im Interface schon etwas "macht" und man in der jeweiligen Funktion nicht nochmals die Funktion schreiben muss. Also etwa so;

        
      interface IHaustier {  
       // Die Methode wird über das Interface nur vorgeschrieben,  
       // daher darf sie keinen Inhalt haben.  
       public function getName() {  
                  return $this->name;  
              }  
      }
      

      Gruss
      Werner

      1. Mehr Sinn würde es für mich machen, wenn die Funktion im Interface schon etwas "macht" und man in der jeweiligen Funktion nicht nochmals die Funktion schreiben muss.

        Ein Interface sagt nur, dass die Klasse die es implementiert etwas bestimmtes kann. Wie diese Klasse das macht, weiß das Interface nicht.

        IHaustier sagt also, ein Haustier "kann getName". Was getName genau tut, kommt aufs jeweilige Haustier an.

        Das was du meinst wäre eine Basisklasse mit einer Funktion die für alle Haustiere gleich ist.

      2. Tach!

        Die Klasse Hund unten nutzt das Interface IHaustier. Aber trotzdem muss man nochmals dieselbe Funktion in der Klasse aufführen bzw. schreiben.
        Mehr Sinn würde es für mich machen, wenn die Funktion im Interface schon etwas "macht" und man in der jeweiligen Funktion nicht nochmals die Funktion schreiben muss.

        Wenn sie schon etwas machen soll, dann kannst du ganz normal erben, eine abstrakte Klasse mit einer konkreten Methode nehmen oder auch Traits ab PHP 5.4. Ich kann auch noch einen anderen Vergleich bemühen: Ein Interface ist nur der Arbeitsvertrag, in dem drinsteht, was du zu tun hast. Und nun musst du dich hinsetzen und diesen Punkt im Vertrag mit Leben füllen. Der Vertrag macht das logischerweise nicht für dich.

        Vielleicht ist das Beispiel mit dem Namen unglücklich gewählt. Das sieht ja so aus, als ob das immer die Eigenschaft name abgreift. Das wäre etwas für eine Elternklasse. Ein Interface kommt eher dann zum Einsatz, wenn Klassen keine gemeinsame Basis haben aber trotzdem gemeinsame Mitglieder haben sollen. Beispielsweise könntest du einen Programmteil haben, der sich um die Persistenz von Dingen kümmert, also um deren dauerhafte Speicherung. Der muss mit viel Dingen zurechtkommen und nicht nur mit solchen mit gemeinsamer Basisklasse. Jede Klasse hat andere Anforderungen, welche Eigenschaften persistiert werden sollen und welche nicht. Zudem hat ja jede Klasse ihre eigenen Eigenschaften, die die Basisklasse nicht kennen kann. Wie kann nun der Persistenzteil diese unterschiedlichen und unabhängigen Objekte sichern? Nehmen wir an, das soll in serialisierter Form geschehen, dann erstellst du ein Interface ISerializable mit dem Methodennamen serialize() (den Rückweg lass ich mal außen vor). Jede Klasse, die persistiert werden kann, implementiert nun dieses Interface und diese Methode. Der Persistenzteil nimmt nur Dinge vom Typ ISerializable entgegen und weiß, dass er davon $ding->serialize() aufrufen kann, woraufhin er als Ergebnis die serialisierten Daten des Objekts bekommt. Vom Rest hat er keine Ahnung - muss er auch nicht.

        dedlfix.

      3. Mehr Sinn würde es für mich machen, wenn die Funktion im Interface schon etwas "macht" und man in der jeweiligen Funktion nicht nochmals die Funktion schreiben muss.

        Wie würdest du das bei flugfähigen Objekten machen? Nehmen wir an es gibt ein Wettfliegen. Alles, was irgendwie aus eigenem Antrieb fliegen kann, darf teilnehmen. Das sind also Menschen mit einem Jetpack, Vögel, Flugzeuge und Baumsamen.
        Da kannst du keine Methode fliegen() für all diese Teilnehmer schreiben, denn was sollte darin stehen? "Schlage mit den Flügeln"? Oh warte, ein Jetpack hat keine Flügel. Und Flugzeuge schlagen nicht mit den Flügeln.
        Trotzdem willst du, dass du als Wettkampfleiter eine Garantie hast, das der Teilnehmer wirklich fliegen kann und nicht einfach abstürzt (wäre nicht so gut für deinen Ruf...).
        Daher müssen alle deine Teilnehmer das Interface "Flugfähig" implementieren (so wie sie eben Fliegen) und voilá, du bist abgesichtert.

        Natürlich kann es passieren, dass ein Teilnehmer in seiner durch das Interface vorgeschriebenen fliegen() Methode nur Quatsch drin stehen hat - dann betrügt er allerdings das Interface und hält sich nicht an die Dokumentation, die ja besagt, dass er fliegen können muss.

        Etwas ähnliches passiert, wenn du beispielsweise in Java die equals Methode anpasst, aber hashcode nicht ebenfalls an die Änderungen anpasst. Das darfst du nicht, denn das kann zu Fehlern führen, was aber nur in der Doku steht; d.h. der Compiler meckert nicht, aber es führt zu logischen Fehlern - genau wie beim Fliegen. Nachher stürzt dein Programm nämlich ab. :P

        http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#equals%28java.lang.Object%29

        1. Hallo

          das Beispiel ist gut. Jetzt wird es mir langsam klarer :-)

          Angenommen ich bekomme von jemanden eine fertige eMail Klasse. Oder bleiben wird bei dem erwähnten Beispiel aus meinem Eingangspost.

          Man muss als Entwickler schon die Klasse genau anschauen und wissen das es ein Interface IHaustier gibt mit der Funktion getName.

          interface IHaustier {
            public function getName();
          }

          Weil rein aus dem Code hier sieht man ja nicht das es in der Klasse ein Interface gibt.

          $einHund = new Hund('Rex');
          $vKatze = new VirtuelleKatze();
          var_dump($einHund->getName());
          var_dump($vKatze->getName());

          Gruss
          Werner

          1. Tach!

            Man muss als Entwickler schon die Klasse genau anschauen und wissen das es ein Interface IHaustier gibt mit der Funktion getName.
            Weil rein aus dem Code hier sieht man ja nicht das es in der Klasse ein Interface gibt.

            Das Interface allein nützt dir nicht viel. Du brauchst auch Anwendungen, die sich darauf berufen. Bei PHP kannst du ja einer Funktion/Methode einen beliebigen Typ als Parameter übergeben. Das heißt, mit genügend Eigendisziplin übergibst du an der Stelle nur Objekte, die die Methode getName() haben und greifst in der Funktion darauf zu. Dann brauchst du auch kein Interface. Das wird erst dann wirklich interessant, wenn du mit Type Hinting die Menge der übergebbaren Dinge auf einen einzigen Typ einschränkst - in dem Fall auf dieses Interface.

            Alternativ kannst du auch ohne Interface das Vorhandensein der Methode getName() prüfen. Mit Interface kannst du diese Prüfung weglassen, weil PHP beim Aufruf das Argument prüft.

            dedlfix.

  2. servus WernerK,

    Was bringt einem das Interface wenn man doch jedes mal in der Klasse die Funktion "getName" aufrufen muss? Dann kann man es doch gleich so machen wie in meiner Version ?

    Interfaces benutze ich als Richtlinien zum Beispiel bei Modulen. Dann habe ich neben der Dokumentation auch im Code Hilfestellungen, wie ich etwas implementieren sollte. Nach Monaten weiß man halt nicht mehr jeden Kniff in der Architektur auswendig. Das, finde ich, ist auch besonders gut bei Projekten, in denen im Team gearbeitet wird. Klar könnte/sollte/würde eine Doku reichen, aber aus Erfahrung weiß ich, dass nicht mal Inline-Kommentaren große Beachtung geschenkt wird..

    der wurzelbert

    --
    "The depressing thing about tennis is that no matter how good I get, I´ll never be as good as a wall."
  3. Was bringt einem das Interface wenn man doch jedes mal in der Klasse die Funktion "getName" aufrufen muss? Dann kann man es doch gleich so machen wie in meiner Version ?

    Ergänzend zu den anderen: interessant wird es dann, wenn Projekte sehr groß werden und viele am gleichen Projekt mitarbeiten. Man könnte natürlich einfach in die Doku schreiben "Alle Tiere haben eine getName() Funktion". Das geht natürlich - nur, wer sagt, dass die Doku gelesen wird? Eben, niemand. Machst du es hingegen als Interface, kann der Compiler meckern, wenn er merkt, dass es gar keine getName() Methode gibt, weil ein Objekt nicht das Interface implementiert.