web-dev-qa-db-de.com

PHP Event-Listener-Best-Practice-Implementierung

Ich versuche, ein CMS-ähnliches System in PHP zu erstellen. so modular und erweiterbar wie möglich.

Könnte mir jemand das Best-Practice-Szenario anbieten, ein Ereignis-Listener-System in PHP (eine sehr vereinfachte Version von Drupal System zum Beispiel) zu erstellen, Hooks und sie in einem kurzen Beispiel umzusetzen, wäre auch schön.

48
H.Josef

Nun, aus Sicht der Implementierung gibt es drei verschiedene Möglichkeiten, dies zu tun (beachten Sie, dass dies OO Entwurfsmuster sind, aber Sie können sie funktional oder prozedural implementieren, wenn Sie möchten).

1. Beobachtermuster

Sie können das Observer Pattern implementieren. Grundsätzlich müsste jede Sache, die Ereignisse auslösen kann, ein Thema sein. Dann sind die Klassen/der Code, die/der Sie anhören möchten, an das gebunden, was sie speziell anhören möchten. Nehmen wir also an, Sie haben einen Controller namens Foo. Wenn Sie es anhören möchten, können Sie $fooController->attach($observer); aufrufen. Wann immer der Controller etwas sagen wollte, schickte er das Ereignis an alle Beobachter.

Dies ist wirklich gut für ein Benachrichtigungssystem geeignet (um zu erweitern, was Klassen tun). Es ist nicht so gut geeignet, um das Verhalten von Code in Echtzeit zu ändern.

2. Decorator Pattern Sie können auch das Decorator Pattern implementieren. Grundsätzlich nehmen Sie das Objekt, das Sie ändern möchten, und "verpacken" es in ein neues Objekt, das das tut, was Sie ändern möchten. Dies ist wirklich gut geeignet, um das Verhalten zu ändern und zu erweitern (da Sie die Funktionalität der umschlossenen Klasse selektiv überschreiben können).

Dies funktioniert sehr gut, wenn Sie Schnittstellen definiert haben und erwarten, dass Objekte diesen entsprechen. Wenn Sie keine Schnittstellen haben (oder diese nicht richtig verwenden), geht das meiste, was das Dekorationsmuster für Sie tun kann, verloren.

Beachten Sie auch, dass dies keine Möglichkeit zum Ausführen von Ereignissen ist, sondern eine Möglichkeit zum Ändern des Objektverhaltens.

3. Mediator Pattern

Sie können auch einen Vermittler verwenden. Grundsätzlich hätten Sie einen globalen Vermittler, der Ihre Zuhörer im Auge behält. Wenn Sie ein Ereignis auslösen möchten, senden Sie das Ereignis an den Mediator. Der Mediator kann dann verfolgen, welche zuhörenden Objekte dieses Ereignis empfangen möchten, und die Nachricht ordnungsgemäß weitergeben.

Dies hat den Vorteil, dass es zentral ist. Das bedeutet, dass mehrere Absender dasselbe Ereignis senden können und es für die Zuhörer keinen Unterschied macht, wer es gesendet hat ...

Ich habe dieses Thema in einem Blogbeitrag erweitert.

130
ircmaxell
/*
 Example 1: 
 event::bind('blog.post.create', function($args = array())
 {
    mail('[email protected]', 'Blog Post Published', $args['name'] . ' has been published');
});

 Example 2: 
 event::trigger('blog.post.create', $postInfo);
*/

class event
{
    public static $events = array();

    public static function trigger($event, $args = array())
    {
        if(isset(self::$events[$event]))
        {
            foreach(self::$events[$event] as $func)
            {
                call_user_func($func, $args);
            }
        }

    }

    public static function bind($event, Closure $func)
    {
        self::$events[$event][] = $func;
    }
}
33
Codebeat

So habe ich es in ein paar Projekten gemacht

Alle Objekte werden mit einer Konstruktorfunktion anstelle des Operators new erstellt.

 $obj = _new('SomeClass', $x, $y); // instead of $obj = new SomeClass($x, $y);

dies hat viele Vorteile gegenüber raw new. Unter dem Gesichtspunkt der Ereignisbehandlung ist es wichtig, dass _new() eine Liste aller erstellten Objekte führt.

Es gibt auch eine globale Funktion send($message, $params), die diese Liste durchläuft und, wenn ein Objekt eine Methode "on_ $ message" verfügbar macht, diese Methode unter Übergabe von Parametern aufruft:

function send() {
    $_ = func_get_args();
    $m = "on_" . array_shift($_);
    foreach($_all_objects as $obj)
        if(method_exists($obj, $m))
            call_user_func_array(array($obj, $m), $_);
}

Zum Beispiel ruft send('load') für jedes Objekt, für das es definiert ist, die Methode on_load Auf.

13
user187291

Wenn Sie PHP 5.3) verwenden (und somit Zugriff auf umfangreiche Abschlüsse haben), würde ich das Ereignis-/Filtersystem in Lithium als Grundlage verwenden AOP Design in PHP.

4
scoates