{
    "slug": "observer_pattern",
    "term": "Observer Pattern",
    "category": "general",
    "difficulty": "intermediate",
    "short": "Defines a one-to-many dependency so that when one object changes state, all its registered observers are notified automatically.",
    "long": "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.",
    "aliases": [
        "observer",
        "event listener pattern",
        "pub-sub pattern"
    ],
    "tags": [
        "general",
        "design-pattern",
        "oop",
        "events"
    ],
    "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."
    ],
    "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."
    ],
    "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."
    ],
    "related": [
        "event_driven",
        "separation_of_concerns",
        "dependency_injection"
    ],
    "prerequisites": [
        "event_driven",
        "domain_events",
        "dependency_injection"
    ],
    "refs": [
        "https://refactoring.guru/design-patterns/observer"
    ],
    "bad_code": "// Direct method calls — tight coupling:\nclass OrderService {\n    public function place(Order $o): void {\n        $this->save($o);\n        $this->emailService->sendConfirmation($o); // Coupled\n        $this->inventoryService->reserve($o);       // Coupled\n        $this->analyticsService->track($o);         // Coupled\n    }\n}\n// Better: dispatch OrderPlaced event; each service subscribes independently",
    "good_code": "interface EventListener {\n    public function handle(object $event): void;\n}\n\nclass EventDispatcher {\n    private array $listeners = [];\n\n    public function listen(string $event, EventListener $listener): void {\n        $this->listeners[$event][] = $listener;\n    }\n    public function dispatch(object $event): void {\n        foreach ($this->listeners[$event::class] ?? [] as $listener) {\n            $listener->handle($event);\n        }\n    }\n}\n\n// Usage\n$dispatcher->listen(OrderPlaced::class, new SendConfirmationEmail());\n$dispatcher->listen(OrderPlaced::class, new UpdateInventory());\n$dispatcher->dispatch(new OrderPlaced($order));",
    "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",
    "severity": "low",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-03-25",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/observer_pattern",
        "html_url": "https://codeclaritylab.com/glossary/observer_pattern",
        "json_url": "https://codeclaritylab.com/glossary/observer_pattern.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Observer Pattern](https://codeclaritylab.com/glossary/observer_pattern) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/observer_pattern"
            }
        }
    }
}