PHP Blogger

Startseite Schreib mir ne Mail! RSS Abo Webnews

Hook- und Callback-Funktionen (Teil 3)

Vor ziemlich genau 100 Jahren hat der PHP Blogger mit einer Serie begonnen, die leider nie zum Ende gekommen ist: Es geht im Hook- und Callback Implementierungen. Teil 1 hat die eine Vererbungstechnik vorgestellt, in Teil 2 haben wir uns einen Callback-Stack angeschaut und weil mich ständig Fragen via Mail zu dem Thema erreichen, habe ich mich entschieden, den 3. Teil doch noch fertig zu stellen ;)

Im Teil 3 werfen wir also einen Blick auf die Listener-Objekte, wie sie in Actionscript zum Einsatz kommen. Die Actionscript-Götter haben mit den Listenern im Prinzip Callback-Pakete geschnürt: Alle zusammengehörigen Callback-Funktionen sind in einem Objekt untergebracht.

Ganz schön praktisch: Auf diese Weise kann man die sogenannten Listener öfter verwenden, muss sie aber nur ein Objekt im Speicher halten. Genau genommen sind Listener natürlich nur eine Abwandlung des Callback-Stacks (Link siehe oben), aber wie immer sind halt die Details entscheident: Im Gegensatz zum Callback-Stack werden die Callback-Funktionen direkt getriggert.

Werfen wir mal einen Blick auf eine Listener-Klasse:

class Listener
{
  function onEvent()
  {
    // Mach irgendwas
  }
}

Ein Objekt, dass diesen Listener verwenden könnte, sieht wie folgt aus:

class EventHost
{
  var $eventListener;

  function EventHost($pEventListener)
  {
    $this->eventListener= $pEventListener;
  }

  function triggerEvent()
  {
    $this->eventListener->onEvent();
  }
}

Der Event-Listener könnte natürlich auch zur Laufzeit ausgetauscht werden. Und genau hier ist auch wieder der Decorator-Ansatz zu sehen. Statt Funktionen statisch in Klassen zu implentieren und durch die Gegend zu vererben, können Objekte Funktionen zur Laufzeit lernen.

In Programmiersprachen, die kompiliert werden, fällt ein solcher Vorteil natürlich noch stärker ins Gewicht. So wird aus einer schwerfälligen Applikation schnell ein Leichtfüssler.

Interessant wird es, wenn die Listener über Rückgabewerte verfügen. Im einfachsten Fall ein Boolean (true oder false). Was könnte man damit anstellen? Natürlich können wir ein solches Pattern dazu verwenden, Standard-Methoden zur Laufzeit beliebig zu überschreiben. Erweitern wir unseren Code erstmal um einen Default-Listener:

class DefaultListener
{
  function onEvent()
  {
    // Macht nix
    return false;
  }
}

Wie man sehen kann, führt der Default-Trigger keine Aktion aus, er liefert lediglich false zurück. Jetzt erweitern wir den EventHost noch um ein paar Zeilen:

class EventHost
{
  var $eventListener;

  function EventHost()
  {
    $this->setEventListener(new DefaultListener());
  }

  function setEventListener($pEventListener)
  {
    $this->eventListener= $pEventListener;
  }

  function triggerEvent()
  {
    if(!$this->eventListener->onEvent())
    {
      // Mach Standard-Zeug
      echo "Default";
    }
  }
}

Was hat sich geändert? Zunächst wird den Event-Listener nicht mehr im Konstruktor gesetzt, sondern über eine entsprechende Funktion “setEventListener”. Im Konstruktor wird der Default-Listener gesetzt, dessen Funktion false zurück liefert.

Sobald der Event getriggert werden soll, wird zunächst der Callback-Listener ausgeführt. Im Falle, das false zurückgeliefert wird, wird eine Standard-Methode ausgeführt. Wenn true zurück geliefert wird, passiert nichts.

Jetzt ein erweiterter Event-Listener:

class EventListener extends DefaultListener
{
  function onEvent()
  {
    // Mach was besseres
    echo "Endgeil";
    // Lass es den EventHost wissen:
    return true;
  }
}

Wenn man jetzt folgenden Code ausführt…

$eventhost= new EventHost();
$eventhost->setEventListener(new EventListener);
$eventhost->triggerEvent();

…erhält man aus Ausgabe “Endgeil!” statt “Default”. Warum muss ich jetzt nicht erklären, oder? Aber für was kann man sich so eine Logik zu nutze machen?

Prinzipiell ist es natürlich die beste Methodik, um es Usern zu erlauben, Frameworks oder Applikationen zu customizen. Ein Mechnismus kann so in nahe zu jede erdenkliche Richtung gebogen werden - ohne den Applikationskern verändern zu müssen.

Die Wordpress-Entwickler sind ein große Fans dieser Vorgehensweise und haben deshalb Actions und Filter großzügig eingesetzt, um Platz für Plugins und Themes zu machen.

Wenn Euch dieser Artikel gefallen hat, gibts demnächst noch einen 4. Teil, der auf die Platzierung von Filtern eingeht und Euch zeigt, wie man seine Applikation durch Filter flexibler machen kann.

Ähnliche Artikel:

  1. Hook- und Callback-Funktionen (Teil 1)
  2. Hook- und Callback-Funktionen (Teil 2)
  3. Suchen (und finden) mit PHP - Teil 2: Die direkte Suche
  4. Suchen (und finden) mit PHP - Teil 1
  5. Wer auf der Welt braucht temporäre Funktionen?

Neq meint dazu:

17. Oktober 2008 um 13:55

Auf jeden Fall interessant. ;)
Ein 4. Teil ist gern gesehen.

alex meint dazu:

17. Oktober 2008 um 14:09

Auf jeden Fall würde ich gerne einen 4. Teil lesen!

Manuel meint dazu:

19. Oktober 2008 um 22:41

Danke für den 3. Teil ;-)
Bin schon gespannt auf den nächsten Teil…

Christoph meint dazu:

20. Oktober 2008 um 18:26

Hi,

interssant auf jeden Fall.
Ich stelle mir gerade nur die Frage, ob das ganze nicht irgendwann zu unwartbar wird?

Christoph

timi meint dazu:

20. Oktober 2008 um 19:03

Hi Christoph,

ein welcher Hinsicht unwartbar? Vererbung ist objektorientiertes Entwickeln wie es schöner nicht sein könnte und Dekorieren ein oft eingesetztes Muster.

Natürlich muss man das Ganze als Technik begreifen, die für modulare Applikationen eingesetzt wird. Jedes Modul oder Plugin wird für sich gekapselt abgelegt und verwaltet, vielleicht sogar in einem eigenen Versionierungsstamm…

Der EventHost könnte dabei zum Applikations-Core gehören, der bzw. die Listener zum Plugin.

Der Vorteil liegt auf der Hand: Sonderfunktionen können problemlos in Modulen organisiert werden, der Kern der Applikation bleibt frei von Sonderlösungen und ist weiterhin universell einsetzbar. Ein Problem, das zum Beispiel die meisten Content-Management-Lösungen haben: Sie werden im Laufe der Zeit immer mehr an den Kunden angepasst (customized) und sind irgendwann nicht mehr ohne weiteres updatefähig.

Wordpress setzt diese Technik ziemlich erfolgreich ein - Module, die nach einem Kernel-Update nicht mehr funktionieren, können einfach abgeschaltet werden. Und wer eine Funktion vermisst oder umgestalten möchte, baut einfach ein Plugin - und aktiviert es.

Manuel meint dazu:

22. Oktober 2008 um 10:03

Macht es WordPress denn genauso wie das hier beschrieben wird mit den Hooks?
Bei xt:Commerce (Veyton) ist es z.B. auch möglich, innerhalb einer Methode eigenen Code (aus einem Plugin) zu platzieren. Kann man das mit der oben beschriebeben Methodik auch realisieren? (siehe Punkt “Pluginsystem” auf http://www.xt-commerce.com/blog/enterprise/xtcommerce-enterprise-status.html)

timi meint dazu:

22. Oktober 2008 um 15:44

Die Mechanik ist sicher ziemlich ähnlich. Statt wie hier im Beispiel nur einen Listener zu verwalten und aufzurufen, kann man natürlich auch mit einem Stack arbeiten und ist dann wesentlich flexibler. Das würde Wordpress-Actions am ehesten entsprechen.

Um gerenderten Code zu manipulieren eignen sich wie in Wordpress verwendete Filter. Dazu mehr im nächsten Teil…

Christoph meint dazu:

23. Oktober 2008 um 08:26

Hi Tim,
ok verstehe, macht natürlich Sinn.
Könnte man das auch mit dem “Dependency-Injection” aus dem Spring Framework vergleichen?

Es ähnelt also dem “Inversion of Control” Konzept?
Nach dem Motto: “Don’t call us, we’ll call you!”.

Christoph

timi meint dazu:

23. Oktober 2008 um 09:01

Hi Christoph,

mit Dependency-Injection hat das nichts zu tun, die bezieht sich in erster Linie auf die Erzeugung von Objekten. Wie das mit Spring umgesetzt ist, kann ich leider nicht beurteilen.

Inversion of Control trifft den Nagel eigentlich auf den Kopf. Es ist tatsächlich eine Art Hollywood-Prinzip: Die Aktion wird erst angefordert und ausgeführt, wenn ein Event eintritt.

Simon meint dazu:

21. November 2008 um 21:16

Hi,
welches Plugin verwendest du eigentlich zum Anzeigen und formatieren von PHP-Quelltext?
Ich bin noch auf der Suche nach einem passenden Wordpress-Plugin.

Simon

Thorsten meint dazu:

30. November 2008 um 01:06

Danke für die Artikel Reihe, ich kann den nächsten Teil gar nicht erwarten :)

Karsten meint dazu:

21. Januar 2009 um 19:55

Ich würde mich über einen 4ten Teil auch sehr freuen : ).

Martin meint dazu:

19. Juni 2009 um 16:15

Ist zwar schon eine Weile her, das du diesen Artikel geschrieben hast, allerdings würde mich der vierte Teil auch sehr interessieren :)

Ludwig meint dazu:

5. September 2009 um 17:20

Wirklich sehr interessant, will dich auch zum 4. Teil ermutigen ;)

Dennis meint dazu:

6. Oktober 2009 um 18:17

Ja allerdings, gespannt bin ich auch mal, ob es einen vierten Teil geben wird! Liest sich sehr interessant! :)

Tom Schultz meint dazu:

12. März 2010 um 09:24

Habe viele Anregungen aus der Serie mitgenommen aber nun möchte ich auch gern wissen wie die Geschichte weitergeht.

scrieler meint dazu:

22. Juni 2010 um 10:00

Sehr schöne Serie zum Verständnis! Würde mich ebenfalls über eine Fortsetzung freuen.

sem meint dazu:

9. Juni 2012 um 20:46

sem…

PHP Blogger: Hook- und Callback-Funktionen (Teil 3) - Ein PHP Blog auf deutsch…

RSS für Kommentare zu diesem Artikel · TrackBack URI

Schreib Deine Meinung