Start · Sprachen · PHP · Referenz · SplObserver

SplObserver

Interface

Definiert die Schnittstelle für Beobachter im Observer-Entwurfsmuster und wird zusammen mit <code>SplSubject</code> verwendet.

seit PHP 5.1.0 Kategorie: oop

Signatur

interface SplObserver

Beschreibung

SplObserver ist Teil der Standard PHP Library (SPL) und stellt eine Schnittstelle für das klassische Observer-Entwurfsmuster (auch Beobachter-Muster genannt) bereit. Klassen, die dieses Interface implementieren, registrieren sich bei einem SplSubject und werden automatisch benachrichtigt, sobald sich der Zustand des Subjects ändert.

Das Interface schreibt genau eine Methode vor: update(SplSubject $subject). Diese wird vom Subject aufgerufen, wenn eine relevante Zustandsänderung eingetreten ist. Über den übergebenen SplSubject-Parameter kann der Observer den aktuellen Zustand des Subjects abfragen.

Typische Anwendungsfälle sind Event-Systeme, Logging, Caching, UI-Aktualisierungen oder jede Situation, in der mehrere Objekte auf Änderungen eines anderen Objekts reagieren sollen, ohne dass enge Kopplung zwischen diesen Objekten entstehen soll.

Für eine vollständige Implementierung des Observer-Musters benötigt man sowohl SplObserver (für Beobachter-Klassen) als auch SplSubject (für das beobachtete Objekt) sowie typischerweise ein SplObjectStorage, um die registrierten Observer effizient zu verwalten.

Beispiele

Einfacher Beobachter für einen Newsfeed

<?php
class NewsAgency implements SplSubject
{
    private SplObjectStorage $observers;
    private string $news = '';

    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 $observer) {
            $observer->update($this);
        }
    }

    public function setNews(string $news): void
    {
        $this->news = $news;
        $this->notify();
    }

    public function getNews(): string
    {
        return $this->news;
    }
}

class NewsReader implements SplObserver
{
    private string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function update(SplSubject $subject): void
    {
        echo "[{$this->name}] Neue Nachricht: " . $subject->getNews() . PHP_EOL;
    }
}

$agency  = new NewsAgency();
$readerA = new NewsReader('Alice');
$readerB = new NewsReader('Bob');

$agency->attach($readerA);
$agency->attach($readerB);

$agency->setNews('PHP 8.4 wurde veröffentlicht!');

$agency->detach($readerB);

$agency->setNews('PHP 9.0 in Planung.');
[Alice] Neue Nachricht: PHP 8.4 wurde veröffentlicht! [Bob] Neue Nachricht: PHP 8.4 wurde veröffentlicht! [Alice] Neue Nachricht: PHP 9.0 in Planung.

Logger als Observer für ein Konfigurations-Subject

<?php
class Config implements SplSubject
{
    private SplObjectStorage $observers;
    private array $data = [];

    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 $observer) {
            $observer->update($this);
        }
    }

    public function set(string $key, mixed $value): void
    {
        $this->data[$key] = $value;
        $this->notify();
    }

    public function getData(): array
    {
        return $this->data;
    }
}

class AuditLogger implements SplObserver
{
    public function update(SplSubject $subject): void
    {
        $data = $subject->getData();
        $last = array_key_last($data);
        echo "[AUDIT] Konfiguration geändert: {$last} = {$data[$last]}" . PHP_EOL;
    }
}

$config = new Config();
$logger = new AuditLogger();
$config->attach($logger);

$config->set('debug', true);
$config->set('timezone', 'Europe/Berlin');
[AUDIT] Konfiguration geändert: debug = 1 [AUDIT] Konfiguration geändert: timezone = Europe/Berlin

// Wichtig · Fallstricke

Hinweis zur Methoden-Signatur: Die Methode update() akzeptiert ein SplSubject-Objekt, aber keinen weiteren Kontext über welche Änderung stattgefunden hat. Für komplexere Szenarien, in denen der Observer den Typ der Änderung kennen muss, empfiehlt es sich, eigene Event-Objekte oder eine erweiterte Schnittstelle zu verwenden.

Zirkuläre Abhängigkeiten vermeiden: Wenn ein Observer in seiner update()-Methode den Zustand des Subjects ändert, kann das zu unendlichen Benachrichtigungsschleifen führen. Entsprechende Schutzmaßnahmen (z. B. ein Sperr-Flag im Subject) sind ratsam.

Alternative: Für sehr komplexe Event-Systeme bieten sich dedizierte Event-Dispatcher-Bibliotheken oder PSR-14-konforme Implementierungen an, die mehr Flexibilität bieten als das einfache SPL-Observer-Paar.