← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Observer Pattern

General PHP 5.0+ Intermediate
debt(d7/e5/b5/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated detection is 'no' and the code pattern (class directly calling methods on multiple classes after state change instead of publishing an event) requires a reviewer to recognise the architectural smell. PHPStan can catch some structural issues but cannot reliably identify missing observer abstractions; the misuse is mostly invisible until a developer reviews the design or runtime symptoms (memory leaks, crash loops, tight coupling) surface.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes defining Subject and Observer interfaces and injecting observers, but this involves creating new interfaces, refactoring the subject class, updating all call sites that previously called methods directly, and wiring observers — a non-trivial refactor across multiple files even if contained to one component.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Applies to web, cli, and queue-worker contexts. A poorly implemented observer setup (no detach, synchronous heavy observers, circular chains) creates an ongoing tax: memory leaks in long-running processes, fragile dispatch loops, and hidden coupling between components that every maintainer must understand and carefully manage. It shapes how new features hook into the system without quite defining the entire system's shape.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field identifies the canonical wrong belief: conflating the Observer pattern with an event bus. Developers familiar with pub-sub systems assume publishers and subscribers are fully decoupled via a broker, but in the Observer pattern the subject holds direct references to observers. Additionally, common_mistakes (memory leaks from undetached observers, exception propagation crashing dispatch, circular chains) are well-documented but routinely hit in practice.

About DEBT scoring →

Also Known As

observer event listener pattern pub-sub pattern

TL;DR

Defines a one-to-many dependency so that when one object changes state, all its registered observers are notified automatically.

Explanation

The Observer (or Event/Listener) pattern decouples the subject (event emitter) from its observers (listeners). Observers register interest with the subject; when the subject's state changes, it notifies all registered observers without knowing their concrete types. In PHP frameworks, this is implemented as event dispatchers (Symfony EventDispatcher, Laravel Events). It is ideal for cross-cutting concerns like logging, cache invalidation, and email notifications that shouldn't pollute domain logic. Avoid overuse — complex event chains are hard to trace and debug.

Common Misconception

Observer pattern and event bus are equivalent. Observer creates direct registration between subject and observer objects. An event bus decouples them completely — publishers and subscribers do not reference each other at all, communicating only through the bus.

Why It Matters

The Observer pattern decouples event producers from consumers — an object fires an event without knowing who is listening, enabling new behaviours to be added by registering new observers.

Common Mistakes

  • Not removing observers when they are no longer needed — memory leaks in long-running processes.
  • Observers that throw exceptions crashing the event dispatch loop — catch inside the observer or the dispatcher.
  • Synchronous observers performing slow operations (email, HTTP calls) — use async dispatch for heavy work.
  • Circular event chains where an observer triggers an event that re-triggers the same observer.

Avoid When

  • The event chain is hard to follow — deeply nested observers triggering other observers cause debugging nightmares.
  • Observers are synchronous and slow — a single slow listener blocks all subsequent listeners and the original caller.
  • The order of observer execution matters and is not guaranteed — use an ordered pipeline instead.
  • You only have one listener — a direct method call is simpler and equally clear.

When To Use

  • Decoupling a publisher from multiple independent consumers that react to the same event.
  • Plugin or extension systems where third-party code needs to hook into core events.
  • Audit logging, cache invalidation, and notifications that should not be in the core business logic.
  • UI frameworks and event-driven architectures where components react to state changes.

Code Examples

✗ Vulnerable
// Direct method calls — tight coupling:
class OrderService {
    public function place(Order $o): void {
        $this->save($o);
        $this->emailService->sendConfirmation($o); // Coupled
        $this->inventoryService->reserve($o);       // Coupled
        $this->analyticsService->track($o);         // Coupled
    }
}
// Better: dispatch OrderPlaced event; each service subscribes independently
✓ Fixed
interface EventListener {
    public function handle(object $event): void;
}

class EventDispatcher {
    private array $listeners = [];

    public function listen(string $event, EventListener $listener): void {
        $this->listeners[$event][] = $listener;
    }
    public function dispatch(object $event): void {
        foreach ($this->listeners[$event::class] ?? [] as $listener) {
            $listener->handle($event);
        }
    }
}

// Usage
$dispatcher->listen(OrderPlaced::class, new SendConfirmationEmail());
$dispatcher->listen(OrderPlaced::class, new UpdateInventory());
$dispatcher->dispatch(new OrderPlaced($order));

Added 15 Mar 2026
Edited 25 Mar 2026
Views 62
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 3 pings T 2 pings F 5 pings S 2 pings S 1 ping M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 1 ping T 0 pings W
No pings yet today
PetalBot 1
Scrapy 12 Amazonbot 9 Perplexity 8 SEMrush 5 Google 3 Majestic 2 Unknown AI 2 Claude 2 Bing 2 ChatGPT 2 Ahrefs 2 Meta AI 1 PetalBot 1
crawler 48 crawler_json 3
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Define a Subject interface with attach/detach/notify and an Observer interface with update — inject observers rather than hardcoding them in the subject
📦 Applies To
PHP 5.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Class directly calling methods on multiple other classes after state change instead of publishing an event
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update


✓ schema.org compliant