web-dev-qa-db-fra.com

PHP Implémentation des meilleures pratiques Event-Listener

J'essaie de créer un système de type CMS en PHP. le rendant aussi modulaire et extensible que possible.

Quelqu'un pourrait-il me proposer le meilleur scénario de création d'un système d'écoute d'événements en PHP (une version très simplifiée de Drupal par exemple), création de hooks) et les mettre en œuvre dans un court exemple serait aussi Nice.

48
H.Josef

Eh bien, il y a vraiment trois façons différentes de le faire du point de vue de l'implémentation (notez qu'il s'agit de modèles de conception OO, mais vous pouvez les implémenter de manière fonctionnelle ou procédurale si vous le souhaitez).

1. Modèle d'observateur

Vous pouvez implémenter Observer Pattern . Fondamentalement, vous auriez chaque chose qui peut soulever des événements être un sujet. Ensuite, les classes/code que vous souhaitez écouter se lient à ce qu'ils veulent écouter spécifiquement. Supposons donc que vous ayez un contrôleur appelé Foo. Si vous voulez l'écouter, vous pouvez appeler $fooController->attach($observer);. Ensuite, chaque fois que le contrôleur voulait dire quelque chose, il enverrait l'événement à tous les observateurs.

C'est vraiment bien adapté à un système de notification (pour étendre ce que font les classes). Ce n'est pas aussi bien adapté pour modifier le comportement du code en temps réel.

2. Décorateur Pattern Vous pouvez également implémenter Decorator Pattern . Fondamentalement, vous prenez l'objet que vous souhaitez modifier et vous "enveloppez" dans un nouvel objet qui fait ce que vous voulez changer. C'est vraiment bien adapté pour modifier et étendre le comportement (puisque vous pouvez remplacer sélectivement les fonctionnalités de la classe encapsulée).

Cela fonctionne très bien si vous avez défini des interfaces et que vous vous attendez à ce que les objets s'y conforment. Si vous n'avez pas d'interfaces (ou si vous ne les utilisez pas correctement), la plupart de ce que le modèle de décorateur peut faire pour vous sera perdu.

Notez également que ce n'est vraiment pas une façon de faire des événements, c'est une façon de modifier le comportement des objets.

3. Modèle de médiateur

Vous pouvez également utiliser un Mediator . Fondamentalement, vous auriez un seul médiateur mondial qui suivrait vos auditeurs. Lorsque vous souhaitez déclencher un événement, vous envoyez l'événement au médiateur. Le médiateur peut alors garder une trace des objets à l'écoute qui souhaitent recevoir cet événement et transmettre correctement le message.

Cela a l'avantage d'être central. Cela signifie que plusieurs expéditeurs peuvent envoyer le même événement, et pour les auditeurs, peu importe qui l'a envoyé ...

J'ai développé ce sujet dans un article de blog.

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

Voilà comment je l'ai fait dans quelques projets

Tous les objets sont créés avec une fonction constructeur au lieu de l'opérateur new.

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

cela a de nombreux avantages par rapport à raw new, du point de vue de la gestion des événements, il est important que _new() conserve une liste de tous les objets créés.

Il y a aussi une fonction globale send($message, $params) qui itère dans cette liste et, si un objet expose une méthode "on_ $ message", appelle cette méthode, en passant des paramètres:

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), $_);
}

Ainsi, par exemple, send('load') appellera la méthode on_load Pour chaque objet qui l'a défini.

13
user187291

Si vous utilisez PHP 5.3 (et avez donc accès à de riches fermetures), le système d'événements/filtres dans Lithium est ce que j'utiliserais comme base pour AOP conception en PHP.

4
scoates