Event Bus und Observer-Muster in PHP
In der modernen Entwicklung von Webanwendungen mit PHP besteht häufig die Notwendigkeit, flexibel auf verschiedene Ereignisse zu reagieren: Senden einer E-Mail nach der Registrierung, Protokollieren von Benutzeraktionen, Aktualisieren des Caches bei Datenänderungen. Für diese Zwecke eignen sich das Observer-Muster und seine Erweiterung – der Event Bus (Ereignisbus) – ideal.
Observer-Muster: Grundlagen
Das Observer-Muster (Beobachter) ist ein Verhaltensentwurfsmuster, das einen Abonnementmechanismus erstellt, der es Objekten ermöglicht, Ereignisse in anderen Objekten zu verfolgen und darauf zu reagieren. Hauptkomponenten:
- Subject (Subjekt) – das Objekt, das Ereignisse erzeugt
- Observer (Beobachter) – das Objekt, das auf Ereignisse reagiert
- Event (Ereignis) – Informationen über die durchgeführte Aktion
Event Bus: Evolution des Observer
Der Event Bus ist ein zentralisierter Bus, der alle Ereignisse in der Anwendung verwaltet. Im Gegensatz zum klassischen Observer, bei dem das Abonnement fest an das Subjekt gebunden ist, bietet der Event Bus:
- Lockere Kopplung von Sendern und Empfängern
- Möglichkeit, Handler zur Laufzeit hinzuzufügen/zu entfernen
- Globalen Zugriff auf den Bus von jedem Teil der Anwendung aus
- Vereinfachtes Testen und Debuggen
Beispiel einer Event-Bus-Implementierung in PHP
Erstellen wir eine einfache, aber funktionale Implementierung eines Event Bus, kompatibel mit PSR-14 (Event Dispatcher).
<?php// Schnittstelle für Ereignisseinterface EventInterface{ public function getName(): string;}
// Basiseereignisclass 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; }}
// Schnittstelle für Handlerinterface 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); } }}?>Praktische Anwendung
Jetzt erstellen wir Handler und demonstrieren die Arbeit des Busses:
<?php// Handler zum Senden einer E-Mailclass SendWelcomeEmailHandler implements EventHandlerInterface{ public function handle(EventInterface $event): void { if (!$event instanceof UserRegisteredEvent) { return; }
echo "Senden der Willkommens-E-Mail an {$event->getEmail()}"; // mail($event->getEmail(), 'Willkommen!', '...'); }}
// Handler für die Protokollierungclass LogUserRegistrationHandler implements EventHandlerInterface{ public function handle(EventInterface $event): void { if (!$event instanceof UserRegisteredEvent) { return; }