HowTo: Ein WordPress-Artiges Hook- und Filtersystem schreiben
Systeme wie WordPress oder Drupal bieten die Möglichkeit ein großes Maß an Kernfunktionalität mit Plugins oder Modulen zu erweitern oder sogar vollständig zu verändern ohne dabei das Kernsystem umschreiben zu müssen.
Der Trick dabei sind function hooks – also Funktionen die durch andere Funktionen erweitert werden können.
Wie sich sowas umsetzen lässt, möchte ich im Folgenden Zeigen.
Der Trick dabei sind function hooks – also Funktionen die durch andere Funktionen erweitert werden können.
Wie sich sowas umsetzen lässt, möchte ich im Folgenden Zeigen.
Das Hook-Register
Was zunächst mal gebraucht wird ist eine Registry, die die Hooks speichert. Der Einfachheit halber wird jeder registrierte Hook einfach an die Liste der bereits registrierten angehängt. Will man mehr Kontrolle ermöglichen, wann genau welcher Hook ausgeführt werden soll müsste man da noch etwas dran basteln.
Der geneigte Leser wird feststellen, dass ich hier die bereits vorgestellte Technik der statischen Variablen verwende.
Der geneigte Leser wird feststellen, dass ich hier die bereits vorgestellte Technik der statischen Variablen verwende.
/**
*
* @staticvar array $hooks
* @param string $action hookable function name
* @param mixed $callback callback function
* @param array $args callback arguments
* @return array
*/
function hookit($action, $callback=null, $args=array())
{
static $hooks = array();
if (!isset($hooks[$action]))
{
$hooks[$action] = array();
}
if (is_null($callback)) return $hooks[$action];
$hooks[$action][] = array($callback, $args);
}
Zunächst wird das Hook-Register als statische Variable deklariert. Dann wird geprüft, ob es für $action schon einen Eintrag im Register gibt. Falls nicht, wird er angelegt.
Wurde keine $callback Funktion übergeben, gibt die Funktion das Register für $action zurück. Ansonsten wird die $callback Funktion an den Stapel angehängt.
Der optionale Parameter $args kann dazu verwendet werden, um Standard-Parameter an die $callback Funktion zu übergeben.
Wurde keine $callback Funktion übergeben, gibt die Funktion das Register für $action zurück. Ansonsten wird die $callback Funktion an den Stapel angehängt.
Der optionale Parameter $args kann dazu verwendet werden, um Standard-Parameter an die $callback Funktion zu übergeben.
Die Aufrufschleife
Als nächstes bauen wir uns eine Funktion, die eine Liste von Hooks der Reihe nach abarbeitet.
/**
*
* @param array $hooks
* @param array $func_args
*/
function run_hooks($hooks, $func_args=array())
{
foreach ($hooks as $hook)
{
list($callable, $args) = $hook;
foreach ($func_args as $n => $val)
$args[$n] = $val;
call_user_func_array($callable, $args);
}
}
Dieser Funktion wird eine Reihe von callbacks in der Form, wie sie im Register abgelegt werden übergeben.
Diese werden der Reihe nach ausgeführt, wobei die Standard-Parameter (soweit vorhanden) durch die jeweiligen aus $func_args ersetzt werden.
Eine Option über die man nachdenken könnte wäre, die callbacks so zu schreiben, dass sie ein boolean übergeben und bei false die weitere Ausführung der Liste abzubrechen.
Diese werden der Reihe nach ausgeführt, wobei die Standard-Parameter (soweit vorhanden) durch die jeweiligen aus $func_args ersetzt werden.
Eine Option über die man nachdenken könnte wäre, die callbacks so zu schreiben, dass sie ein boolean übergeben und bei false die weitere Ausführung der Liste abzubrechen.
Eine Hook-Fähige Funktion
Im Grunde war’s das schon. Natürlich brauchen wir jetzt noch die ein- oder andere Funktion, die sich durch hooks erweitern lässt.
Die könnte Beispielsweise so aussehen:
Die könnte Beispielsweise so aussehen:
function the_hooked()
{
run_hooks(hookit(__FUNCTION__), func_get_args());
}
Offensichtlich macht diese Funkion nichts anderes als die callbacks ausführen zu lassen, die sich für ihren Namen registriert haben.
Wurde also kein callback für die Funktion registriert, passiert beim Aufruf überhaupt nichts.
Wurde also kein callback für die Funktion registriert, passiert beim Aufruf überhaupt nichts.
Einen Hook registrieren und ausführen
zum Testen fehlt jetzt eigentlich nur noch eine Funktion, die wir für the_hooked() registrieren und ausführen können.
Da reicht ja was einfaches wie die hier:
Da reicht ja was einfaches wie die hier:
function say_hello()
{
echo "ich soll hallo sagen, also: Hallo!";
}
Ziemlich unspektakulär aber dient ja nur als proof of concept.
Jetzt muss say_hello() nur noch registriert werden und schon haben wir the_hooked() beigebracht Hallo zu sagen.
Jetzt muss say_hello() nur noch registriert werden und schon haben wir the_hooked() beigebracht Hallo zu sagen.
hookit('the_hooked', 'say_hello');
the_hooked();
Filter Hooks
auf ähnliche Weise kann man auch filter definieren. Der entscheidende Unterschied liegt darin, dass den Filter Funktionen der zu Filternde Inhalt übergeben werden muss und diese ihrerseits den gefilterten Content wieder zurück geben müssen. Letzterer wird dann wieder an den nächsten Filter übergeben.
Kommentare: 1
This subject has been up for argument fairly a lot of instances but not one of the posts were as comprehensive as yours. Admin I hope to see this kind of top quality posts from you in the future.