• Projektwerkstatt: Pattern Helper

    von am 14. Februar 2009

    Heute gibt es mal wieder eine Idee direkt vom PHP Meister Nils. Gut, vielleicht kein Großmeister, aber bestimmt die Person, die in den letzten Monaten am häufigsten über PHP gebloggt hat in ganz Deutschland.

    Meine heutige Idee kam mir bei der Arbeit, als ich mal wieder einen Dekorator basteln musste. Wie ihr vielleicht wisst, muss ich beim Dekorierer Entwurfsmuster gegen ein bestimmtes Interface programmieren und die meisten Methoden über Delegation an das Ursprungsobjekt weiterleiten. Methoden, die ich erweitern will würde ich dann einfach erweitern, statt zu delegieren. Wenn ihr meine komische Erklärung nicht versteht, was ich mal vermute, dann schaut euch einfach den Beitrag auf Wikipedia an oder kauft euch das Buch von Stefan Schmidt. Moment da fällt mir ein, dass ich ja selbst schon was geschrieben habe.

    Im Moment habe ich das Problem, wenn ich viel mit Delegation arbeite, dass ich viele Methoden stupide weiterleiten, eben delegieren, muss. Habe ich ein Interface mit 20 Methoden, so muss ich die alle in meiner neuen Klasse implementieren. Und genau dies könnte doch eine Tool übernehmen. Als Input bekommt es einen Klassennamen und spuckt ein eine Klasse aus, die nichts macht, als alles weiterzuleiten, was es so an Funktionen gibt.

    Machen wir mal ein kleines Beispiel:

    interface iBlog
    {
      public function schreibeEintrag( $eintrag );
      public function loescheEintrag( $id );
    }

    Versuchen wir es mal ganz einfach zu halten, da die Idee ja auch ganz einfach ist. Geben wir jetzt dieses Interface oder eine Klasse, die davon abgeleitet wurde in unseren Generator, so erhalten wir folgendes:

    class BlogDelegate implements iBlog
    {
      private $blog;
    
      public function __construct( iBlog $blog )
      {
        $this->blog = $blog;
      }
    
      public function schreibeEintrag( $eintrag )
      {
        return $this->blog->schreibeEintrag( $eintrag );
      }
    
      public function loescheBeitrag( $id )
      {
        return $this->blog->loescheBeitrag( $id );
      }
    }

    Während ich den Code tippe, merke ich wie stupide diese Aufgabe wirklich ist. Über Refelction sollte das doch kein Problem sein, vielleicht sollte man auch die IDE mit einbeziehen. Ich meine das Zend Studio hat ja schon die Möglichkeit setter und getter automatisiert zu setzen. So eine delegate-Erstellungs-Methode wäre doch auch toll.

    Vielleicht schreibe ich mal sowas als externes Tool, dass man integrieren kann. Mal schauen.

    Nils Langner

    Auch wenn Ihr es mir nicht glauben werdet, aber ich habe nichts gegen PHP. Ich rege mich einfach nur gerne auf. Ok so schlimm ist es auch nicht. Eigentlich wollte ich schon immer einen Blog haben und da ...

    Zum Profil von Nils Langner

    7 Kommentare »


    • Stephan Hochdoerfer
      am 14. Februar 2009 um 09:54 Uhr

      Mit Hilfe der magic Methode __call könntest du recht einfach die Delegation übernehmen. In deiner __call Methode könntest du mit method_exists prüfen ob die Methode im Zielobjekt existiert und dementsprechend rufen.

      Das ganze kann sogar als abstrakte Klasse implementiert werden, mit dem Vorteil dass du in deinen konkreten Kindklassen manuell die Methoden selbst implementieren könntest falls du eine “Spezialbehandlung” vornehmen möchtest.


    • Ingo
      am 14. Februar 2009 um 13:33 Uhr

      NetBeans kann aus einem Interface schon recht gut eine Klasse erzeugen. Damit hat man nur noch die halbe schreibarbeit ;-)


    • admin
      am 14. Februar 2009 um 20:59 Uhr

      @Stefan: Mir der __call Methode hast du das wirkjlich große Problem, dass du auf einmal keine Interfaces mehr verwenden kannst. Denn wenn du die Methoden nicht explizit definierst kackt dir der Interpretor ab.

      @Ingo: Zend Studio kann es auch. Habe nur noch nicht rausgefunden, wie ich mir für dieses Feature einen Shortcut lege.


    • Timo Holzherr
      am 16. Februar 2009 um 00:12 Uhr

      __call ist ein wunderbares Sprachkonstrukt von PHP und hilft nicht nur dabei, dass andere Entwickler eigentlich gar nicht mehr wissen, was die Klasse tatsächlich macht. (Immerhin hat wohl keine IDE der Welt bei einer Klasse ohne ein Interface und ohne konkrete Methoden eine Chance anzuzeigen, welche Methoden die Klasse zur Verfügung stellt.) Auch die Dokumentation der Methoden, die durch __call abgedeckt werden, ist dadurch quasi obsolet geworden.

      Hmm, das ist wohl ein sehr religiöses Thema…


    • admin
      am 16. Februar 2009 um 08:41 Uhr

      @Timo: Wir hatten ja schon mal darüber geredet, dass wir in unserem Projekt schon mal diesen __call Hack angewendet haben. Da war es aber so, dass es keine Interfaces gab und die Klassen eh noch in PHP4 waren, man also Probleme hatte, private von public Methoden zu unterscheiden, was eine unendlich lange Liste von Delegationen bedeutet hätte. Ich finde, da es in einem solchen Fall legitim ist. Man darf aber nie vergessen, dass es trotzdem nicht schön ist. Bei uns heißt er auch wirklich “uglyDecorator”.

      @All: Auf meiner Liste steht noch ein Artikel genau über das Thema.


    • Stephan Hochdoerfer
      am 16. Februar 2009 um 08:56 Uhr

      @Timo: Grundsätzliche stimme ich dir natürlich zu. Interfaces sind “sauberer” und sollten primär Verwendung finden. Das heißt aber nicht dass __call keinen Sinn macht. Beispielweise nutzen wir die _call Methodik um bestimmte Methoden eines Objekts (die einem bestimmten, definierten Interface entsprechen) per Webservice zu ansprechbar zu machen. Ganz grob formuliert delegiert der Webservice Wrapper die Aufrufe via __call an das verknüpfte Objekt. In dem Fall arbeiten die Entwickler nicht direkt gegen das Wrapper Objekt sondern gegen den Webservice. Da es keine Code-Completion für Webservices gibt (oder doch?) ist zumindest in dem Fall dein Argument ausgehebelt (imho) :)


    • Timo
      am 16. Februar 2009 um 09:48 Uhr

      Hallo Stephan,

      es gibt immer Ausnahmen und deshalb sicherlich Situationen, in denen die Verwendung von __call der richtige Weg ist. Wichtig ist es meiner Meinung nach, die Nachteile zu kennen und sich über die Konsequenzen im Klaren zu sein.

      Für die Definition und Dokumentation von Webservices gibt es je nach Service andere Werkzeuge. Beispielsweise bietet SOAP mit der WSDL eine wunderbare Möglichkeit, Schnittstellen zu definieren. In Programmiersprachen wie Java gibt es Tools, die aus WSDL-Definitionen Stub-Klassen generieren, die dann auch wieder Code-Completion für die Entwicklungsumgebung bieten. Ob es soetwas für PHP auch gibt, weiß ich jedoch nicht.

      Fazit: Natürlich ist die Verwengung von __call *nicht immer* schlecht, es ist jedoch angebracht 2x darüber nachzudenken, ob es wirklich die beste Lösung ist.

      Grüße,
      Timo

    RSS Feed für Kommentare zu diesem Artikel. TrackBack URL

    Hinterlasse einen Kommentar

    Werbung
    PHP Magazin
    Ausgabe 02/2010

    Dieses Mal mit Artikeln zu den Themen OpenSocial und Apache Shindig, Graphentheorie, Smarty3

    t3n
    Ausgabe 19

    Social Media (R)evolution. Weitere Themen sind noSQL, Crowdsourcing ...

    PHP Journal
    Ausgabe 2/2010

    PHP & Windows optimal nutzen, die besten PHP-CMS im Überblick, Google-API mit Zend Framework nutzen.

    Wir wurden schon öfters gefragt, ob man uns nicht irgendwie unterstützen kann. Die Antwort war immer einfach: Klar! Am einfachsten ist es eure nächsten Einkäufe bei Amazon über unsere Link abzuwickeln. Damit würdet ihr uns schon sehr helfen. Über Co-Autoren freuen wir uns aber noch mehr.