Event Bus et le pattern Observer en PHP
Dans le développement moderne d'applications web en PHP, il est souvent nécessaire de réagir de manière flexible à divers événements : envoi d'email après une inscription, journalisation des actions des utilisateurs, mise à jour du cache lors de la modification de données. Pour ces objectifs, le pattern Observer et son extension — l'Event Bus (bus d'événements) — sont parfaitement adaptés.
Le pattern Observer : bases
Le pattern Observer (Observateur) est un modèle de conception comportemental qui crée un mécanisme d'abonnement permettant à certains objets de surveiller et de réagir aux événements se produisant dans d'autres objets. Composants principaux :
- Subject (Sujet) — l'objet qui génère les événements
- Observer (Observateur) — l'objet qui réagit aux événements
- Event (Événement) — l'information sur l'action qui s'est produite
Event Bus : évolution de l'Observer
L'Event Bus est un bus centralisé qui gère tous les événements dans l'application. Contrairement à l'Observer classique où l'abonnement est strictement lié au sujet, l'Event Bus offre :
- Un couplage faible entre les expéditeurs et les destinataires
- La possibilité d'ajouter/supprimer des gestionnaires pendant l'exécution
- Un accès global au bus depuis n'importe quelle partie de l'application
- Des tests et un débogage simplifiés
Exemple d'implémentation d'un Event Bus en PHP
Créons une implémentation simple mais fonctionnelle d'un Event Bus, compatible avec PSR-14 (Event Dispatcher).
<?php// Interface d'événementinterface EventInterface{ public function getName(): string;}
// Événement de baseclass UserRegisteredEvent implements EventInterface{ public function __construct( private string $email, private string $username ) {}
public function getName(): string { return 'user.registered'; }
public function getEmail(): string { return $this->email; }
public function getUsername(): string { return $this->username; }}
// Interface du gestionnaireinterface EventHandlerInterface{ public function handle(EventInterface $event): void;}
// Event Busclass EventBus{ private array $listeners = [];
public function addListener(string $eventName, EventHandlerInterface $handler): void { $this->listeners[$eventName][] = $handler; }
public function removeListener(string $eventName, EventHandlerInterface $handler): void { if (!isset($this->listeners[$eventName])) { return; }
$this->listeners[$eventName] = array_filter( $this->listeners[$eventName], fn($h) => $h !== $handler ); }
public function dispatch(EventInterface $event): void { $eventName = $event->getName();
if (!isset($this->listeners[$eventName])) { return; }
foreach ($this->listeners[$eventName] as $handler) { $handler->handle($event); } }}?>Utilisation pratique
Créons maintenant des gestionnaires et démontrons le fonctionnement du bus :
<?php// Gestionnaire d'envoi d'emailclass SendWelcomeEmailHandler implements EventHandlerInterface{ public function handle(EventInterface $event): void { if (!$event instanceof UserRegisteredEvent) { return; }
echo "Envoi de l'email de bienvenue à {$event->getEmail()}"; // mail($event->getEmail(), 'Bienvenue !', '...'); }}
// Gestionnaire de journalisationclass LogUserRegistrationHandler implements EventHandlerInterface{ public function handle(EventInterface $event): void { if (!$event instanceof UserRegisteredEvent) { return; } Aussi dans la bibliothèque
Conteneur d'injection de dépendances pour Go (Golang) — wire, dig, fx
node-cron — Planificateur de tâches pour Node.js
Configuration d'applications en Go : bonnes pratiques et outils
Internationalisation (i18n) en C# (.NET) : guide complet
Jetons JWT en Swift : guide complet pour travailler avec les JSON Web Tokens