Navigation
 Startseite
 Fachbücher
 Anzeigenmarkt
 Forum
 Webmaster News
 Script Newsletter
 Kontakt
 Script Installation
 Php
 Php Tutorials
 Lernpfade
 Webhoster Vergleich
 Impressum

Community-Bereich
 kostenlos Registrieren
 Anmelden
 Benutzerliste

Script Datenbank
 Script Archiv
 Script Top 20
 Screenshots
 Testberichte

Suche
 

Unsere Php Scripts
 Counter Script
 Umfrage Script
 Bilder Upload Script
 Terminverwaltung
 Simple PHP Forum
 RSS Grabber

Tools und Generatoren
 .htpasswd Generator
 md5 Generator
 base64 Generator
 Markdown to HTML
 Colorpicker
 Unix timestamp Tool
 Unit Test Generator
 TLD Liste
 Webkatalog‑Verzeichnis

Artfiles.de
Bietet Serviceorientierte...
https://www.Artfiles.de
Hosterplus.de
Bekommen Sie Speicherplatz (Webspace), Domains...
https://www.Hosterplus.de
 
 
 

PHP Observer Pattern: Events zwischen Objekten weiterleiten

Sie befinden sich: Home > Php Tutorial > PHP Observer Pattern: Event...

PHP Observer Pattern: Events zwischen Objekten weiterleiten
Eintrag am:
20.07.2026
Hits / Besucher:
14
Sprache:
  Deutsch
Tutorial Art:
eigenes
Eingetragen von:
Merkliste:
 
Beschreibung

Sobald in einer Anwendung eine einzige Aktion mehrere Reaktionen auslösen soll, stellt sich die Frage nach sauberer Kopplung zwischen den beteiligten Objekten. Das Observer Pattern ist die klassische Antwort darauf und gehört zu den am häufigsten genutzten Entwurfsmustern in der PHP-Welt. Dieser Artikel führt Schritt für Schritt durch Subject, Observer und die Methoden attach, detach und notify und ordnet das Muster am Ende in den heutigen PSR-14-Standard ein.

Was ist das PHP Observer Pattern?

Wer in einer PHP-Anwendung an einer Stelle eine Änderung auslöst, die mehrere andere Komponenten interessiert (eine neue Bestellung soll eine E-Mail, eine Statistik-Aktualisierung und einen Webhook auslösen), kann diese Empfänger entweder fest verdrahten oder lose koppeln. Genau die lose Kopplung ist das Versprechen vom Observer Pattern in PHP: Ein Subject sendet eine Benachrichtigung an alle registrierten Observer, ohne sie im Detail zu kennen, und sobald sich der Zustand ändert, werden alle Listener informiert.

Illustration zum Tutorial: PHP Observer Pattern: Events zwischen Objekten weiterleiten

Bevor Subject- und Observer-Interfaces im Detail folgen, ein kurzer Blick auf die historische Einordnung und den heutigen PSR-14-Standard.

Das Observer Design Pattern ist eines der am häufigsten genutzten Verhaltensmuster der Gang of Four und liegt unter anderem dem WordPress-Hook-System, dem Symfony EventDispatcher und vielen Domain-Event-Implementierungen zugrunde. In modernen PHP-Codebasen gehört es zu den meistgenutzten Designmustern überhaupt, und wer es einmal in der eigenen Anwendung sauber eingesetzt hat, will es nicht mehr missen. Dieses Tutorial führt das Pattern Schritt für Schritt ein. Wir beginnen mit dem Einsatz als Designmuster in eigenen Interfaces, gehen kurz auf die SPL-Variante ein und stellen das Ganze dem PSR-14-Standard für Event-Dispatching gegenüber.

Subject und Observer als Interfaces im PHP Observer Pattern

Den Kern vom PHP Observer Pattern bilden zwei Interfaces. Das Subject sammelt Observer und benachrichtigt sie. Der Observer reagiert auf die Benachrichtigung. Ein eigenes Interfaces-Paar bringt mehr Flexibilität beim Typing als die SPL-Varianten.

<?php

interface Observer
{
public function update(Subject $subject): void;
}

interface Subject
{
public function attach(Observer $observer): void;
public function detach(Observer $observer): void;
public function notify(): void;
}

Die update()-Methode bekommt das Subject übergeben, damit der Observer den geänderten Wert beim Subject abrufen kann (Pull-Variante). Alternativ könnte man bei notify() das geänderte Datum direkt mitgeben (Push-Variante). In der Praxis ist die Pull-Variante flexibler, weil sich das Subject erweitern lässt, ohne alle Observer-Signaturen anzufassen.

Klassische Implementierung mit attach, detach und notify

Ein Subject braucht drei Methoden: attach() registriert einen Observer, detach() entfernt ihn wieder, und notify() informiert alle registrierten Observer. Die Funktion spl_object_id() liefert eine eindeutige Id pro Objektinstanz und sorgt dafür, dass derselbe Observer nicht versehentlich mehrfach registriert wird.

<?php

final class TemperatureSensor implements Subject
{
/** @var Observer[] */
private array $observers = [];
private float $temperature = 0.0;

public function attach(Observer $observer): void
{
$this->observers[spl_object_id($observer)] = $observer;
}

public function detach(Observer $observer): void
{
unset($this->observers[spl_object_id($observer)]);
}

public function notify(): void
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}

public function setTemperature(float $value): void
{
$this->temperature = $value;
$this->notify();
}

public function getTemperature(): float
{
return $this->temperature;
}
}

Sobald setTemperature() aufgerufen wird, ruft das Subject intern notify() und alle registrierten Observer reagieren. Die Observer wissen nichts voneinander, und das Subject muss seine Empfänger nicht im Detail kennen.

Anwendungsfall Sensor mit mehreren Empfängern

Mit dem Subject im Rücken lassen sich beliebige Observer schreiben. Ein Display zeigt den aktuellen Wert an, ein Logger schreibt ihn in die Datei, ein Alarm reagiert nur auf Werte oberhalb einer Schwelle. Dank instanceof können Observer prüfen, ob das Subject von einem für sie relevanten Typ ist.

<?php

final class DisplayObserver implements Observer
{
public function update(Subject $subject): void
{
if ($subject instanceof TemperatureSensor) {
echo 'Display: ' . $subject->getTemperature() . " Grad" . PHP_EOL;
}
}
}

final class AlarmObserver implements Observer
{
public function update(Subject $subject): void
{
if ($subject instanceof TemperatureSensor && $subject->getTemperature() > 80.0) {
echo "ALARM: Temperatur zu hoch!" . PHP_EOL;
}
}
}

$sensor = new TemperatureSensor();
$sensor->attach(new DisplayObserver());
$sensor->attach(new AlarmObserver());

$sensor->setTemperature(85.0);
/* Display: 85 Grad
ALARM: Temperatur zu hoch! */

Wer einen weiteren Observer ergänzen möchte (etwa einen Webhook, der den Wert an eine externe API sendet), schreibt eine neue Klasse, die Observer implementiert, und ruft attach(). Der Sensor-Code bleibt völlig unangetastet.

flowchart TD
    A[Subject aendert Zustand] --> B[notify]
    B --> C[Observer 1 Display]
    B --> D[Observer 2 Logger]
    B --> E[Observer 3 Alarm]

SplSubject und SplObserver als SPL-Variante vom PHP Observer Pattern

PHP bringt mit SplSubject, SplObserver und SplObjectStorage eine Standard-Implementierung vom PHP Observer Pattern mit. Die Interfaces sind seit PHP 5.1 verfügbar und bis heute nutzbar. In modernen Codebasen sieht man sie nur noch selten, weil eigene Interfaces präziseres Typing erlauben und die Methoden-Signaturen nicht durch die generische SPL-API gebunden sind.

<?php

final class SplSensor implements SplSubject
{
private SplObjectStorage $observers;
private float $temperature = 0.0;

public function __construct()
{
$this->observers = new SplObjectStorage();
}

public function attach(SplObserver $observer): void
{
$this->observers->attach($observer);
}

public function detach(SplObserver $observer): void
{
$this->observers->detach($observer);
}

public function notify(): void
{
foreach ($this->observers as $o) {
$o->update($this);
}
}
}

SplObjectStorage ist als Sammlung speziell für Objekte gedacht und übernimmt die Doppel-Registrierungs-Prüfung automatisch. Wer die SPL-Variante nimmt, spart sich den Umgang mit spl_object_id, gibt im Gegenzug aber die freie Wahl der Methoden-Signaturen auf.

Vergleich zu PSR-14 EventDispatcher

In größeren Anwendungen reicht das klassische Subject-Observer-Schema oft nicht mehr aus. Sobald viele unterschiedliche Events auftreten, würde jede Subject-Klasse eine eigene Observer-Verwaltung brauchen. Genau hier setzt PSR-14 an: ein zentraler EventDispatcher kümmert sich um die Verteilung, und ein ListenerProvider liefert pro Event-Typ die zuständigen Listener.

<?php

/* PSR-14: ein generischer Event-Dispatcher mit einem
ListenerProvider, der zu jedem Event-Objekt die passenden
Listener liefert. Vorteil: das Subject muss nicht jedes
Listener-Set selbst halten, das uebernimmt der Dispatcher zentral */

final class TemperatureChanged
{
public function __construct(public readonly float $value) {}
}

interface EventDispatcher
{
public function dispatch(object $event): object;
}

/* Das Subject ruft nur noch:
$dispatcher->dispatch(new TemperatureChanged(85.0));
und alle registrierten Listener werden ausgeloest */

Wer Symfony, Laravel oder Slim nutzt, hat in der Regel bereits einen PSR-14-Dispatcher zur Verfügung. Für kleine Anwendungen oder Plugins ist das klassische PHP Observer Pattern dagegen völlig ausreichend und braucht keine externe Abhängigkeit. Die Frage, ob ein eigenes Subject-Observer reicht oder ob ein zentraler Dispatcher die bessere Wahl ist, lässt sich grob an drei Punkten festmachen: Anzahl der Event-Typen (mehr als 5 spricht für Dispatcher), Anzahl der Listener pro Event (mehr als 3 spricht für Dispatcher) und ob mehrere unabhängige Module Listener registrieren sollen (klares Argument für Dispatcher).

Ein weiterer Vorteil von PSR-14 ist die Idee der stoppable events. Ein Event-Objekt kann signalisieren, dass keine weiteren Listener mehr ausgeführt werden sollen. Das lässt sich im klassischen PHP Observer Pattern zwar nachbauen, ist aber keine Standard-Funktion und erzeugt zusätzliche Komplexität im Subject. Wer solche Anforderungen hat, ist mit einer fertigen PSR-14-Bibliothek besser bedient.

Push-Variante mit Event-Objekt

Statt das Subject im update() als Ganzes zu übergeben (Pull-Variante), kann ein dediziertes Event-Objekt mitgereicht werden. Die Observer bekommen damit nur die Daten, die wirklich relevant sind, und das Subject bleibt gekapselt. Diese Push-Variante ist konzeptionell näher an PSR-14 und fühlt sich vertraut an, sobald später ein Dispatcher dazukommt.

<?php

final class TemperatureChangedEvent
{
public function __construct(public readonly float $value) {}
}

interface PushObserver
{
public function onTemperatureChanged(TemperatureChangedEvent $event): void;
}

final class PushSensor
{
/** @var PushObserver[] */
private array $observers = [];

public function attach(PushObserver $observer): void
{
$this->observers[spl_object_id($observer)] = $observer;
}

public function setTemperature(float $value): void
{
$event = new TemperatureChangedEvent($value);
foreach ($this->observers as $observer) {
$observer->onTemperatureChanged($event);
}
}
}

Der Vorteil: Observer müssen keine instanceof-Prüfung mehr machen, weil das Event seine Daten direkt mitbringt. Der Nachteil: Wer das Event später um ein neues Feld erweitert, muss alle Observer-Signaturen mitziehen oder ein neues Event-Objekt einführen. Für kleine, klar abgegrenzte Subjects ist Push die saubere Wahl, für breite Generic-Subjects bleibt Pull flexibler.

Priorisierte Observer

Wenn die Reihenfolge der Benachrichtigung wichtig ist (Logger zuerst, Webhook zuletzt), reicht das einfache Array nicht mehr aus. Eine kleine Erweiterung um eine Priorität macht das Pattern sortierbar, ohne den Aufrufer-Code zu ändern.

<?php

final class PrioritySensor implements Subject
{
/** @var array<int, array{observer: Observer, priority: int}> */
private array $observers = [];

public function attach(Observer $observer, int $priority = 0): void
{
$this->observers[spl_object_id($observer)] = [
'observer' => $observer,
'priority' => $priority,
];
}

public function detach(Observer $observer): void
{
unset($this->observers[spl_object_id($observer)]);
}

public function notify(): void
{
$sortiert = $this->observers;
/* Hoehere Prioritaet zuerst */
usort($sortiert, fn($a, $b) => $b['priority'] <=> $a['priority']);
foreach ($sortiert as $eintrag) {
$eintrag['observer']->update($this);
}
}
}

/* $sensor->attach(new LoggerObserver(), 100); // laeuft als erstes
$sensor->attach(new WebhookObserver(), 0); // laeuft danach */

Die Sortierung passiert bei jedem notify(). Für Subjects mit hohem Notify-Aufkommen lohnt sich Caching der sortierten Liste, sobald attach/detach selten passieren. PSR-14-Implementierungen wie der Symfony EventDispatcher liefern diese Mechanik im ListenerProvider fertig mit, das obige Beispiel zeigt das Grundprinzip in 20 Zeilen.

Stolperfallen und Best Practices für das PHP Observer Pattern

Im Alltag lauern beim PHP Observer Pattern drei typische Fallen. Erstens: Wer Observer per array[] = $observer registriert, kann denselben Observer mehrfach hinzufügen. Mit spl_object_id() als Schlüssel oder SplObjectStorage ist das ausgeschlossen.

Zweitens blockieren langsame Observer den Notify-Loop. Wenn ein Observer eine externe API ruft, die zwei Sekunden braucht, wartet das Subject zwei Sekunden. Für solche Fälle ist eine Queue (etwa per enqueue mit asynchronen Workern) die bessere Lösung. Drittens entstehen in Long-Running-Prozessen Memory-Leaks, wenn Observer nicht abgemeldet werden. In klassischen PHP-Web-Requests spielt das keine Rolle, weil der Prozess am Ende des Requests endet, in CLI-Tools mit Schleifen oder in Workern muss man darauf achten.

Eine vierte Stelle, die im Code-Review oft auftaucht, ist die Reihenfolge der Benachrichtigungen. Das PHP Observer Pattern sieht keine Garantie über die Reihenfolge der Observer vor. Wer auf eine bestimmte Reihenfolge angewiesen ist (zum Beispiel: Logger immer als erstes, Webhook immer als letztes), sollte das nicht implizit über die Reihenfolge des attach()-Aufrufs steuern, sondern explizit über Prioritäten. Genau das bietet PSR-14 mit dem ListenerProvider, in eigenen Implementierungen lässt sich eine sortierte Observer-Liste leicht nachrüsten.

Eine letzte Empfehlung betrifft die Sichtbarkeit der Observer im Code. Wer ein Subject in einem großen System einsetzt, verteilt die Logik auf viele Klassen, ohne dass auf den ersten Blick erkennbar ist, welche Observer am Ende reagieren. Das ist die Kehrseite der losen Kopplung. In modernen IDEs hilft eine gute Namenskonvention, etwa Suffix Listener oder Subscriber und ein zentraler Registrierungspunkt im Bootstrap. So bleibt die Übersicht erhalten, und neue Teammitglieder finden schneller heraus, was bei einem Event tatsächlich passiert.

Fazit zum PHP Observer Pattern

Das PHP Observer Pattern ist ein bewährtes Werkzeug für lose gekoppelte Reaktion auf Zustandsänderungen. Wer ein Subject mit attach, detach und notify und ein paar Observer braucht, ist mit eigenen Interfaces oder den SPL-Varianten gut bedient. Sobald viele Events durch das System fließen oder externe Listener aus mehreren Modulen registriert werden sollen, lohnt sich der Wechsel auf einen PSR-14 EventDispatcher. Das Pattern bleibt aber die Grundlage und ist auch heute noch der schnellste Weg, eine 1:n-Benachrichtigung in PHP sauber zu implementieren.

 

Tags:

 

 

Kommentare (0)

Noch keine Kommentare. Sei der Erste!

Melde dich an, um einen Kommentar zu schreiben.
Bücherregal mit drei Büchern: 'PHP 4 - Grundlagen und Profiwissen' von Hanser Verlag, 'Webdesign in a Nutshell' von O'Reilly Verlag, und 'Webgestaltung' von Galileo Computing.