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

PSR-14: Event Dispatcher

Style PHP 7.2+ Intermediate
debt(d5/e5/b5/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5), phpstan/deptrac per detection_hints can detect tight coupling to framework-specific dispatchers vs. PSR-14 interface usage, but it requires configured rules.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5), swapping a framework event system to PSR-14 interface requires changing listener registration, event class signatures, and dispatch call sites across the event subsystem.

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

Closest to 'persistent productivity tax' (b5), since applies_to spans web/cli/queue contexts and events are typically dispatched throughout the codebase, the event abstraction shapes many work streams but isn't fully system-defining.

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

Closest to 'notable trap' (t5), per misconception developers assume PSR-14 covers async/queued dispatch and priorities, but it's strictly synchronous in-process — a documented gotcha most learn after hitting it.

About DEBT scoring →

Also Known As

PSR-14 PSR-14 event dispatcher EventDispatcherInterface

TL;DR

Standard EventDispatcherInterface and ListenerProviderInterface for framework-agnostic event dispatch and handler registration.

Explanation

PSR-14 separates event dispatch (EventDispatcherInterface::dispatch($event)) from listener registration (ListenerProviderInterface::getListenersForEvent($event)). Any object can be an event; stoppable events implement StoppableEventInterface. This decouples producers from consumers and allows mixing listeners from different libraries. Implementations include Symfony EventDispatcher and league/event. The standard enables plugin architectures where third-party code attaches listeners without modifying the dispatching class — following Open/Closed Principle. Keep events as simple data-carrying objects; avoid placing behaviour in event classes.

Common Misconception

PSR-14 standardises event systems including event queuing and async dispatch. PSR-14 only covers synchronous in-process event dispatching — async dispatch, priorities, and stopping propagation details are left to implementations.

Why It Matters

PSR-14 defines a standard event dispatcher interface — components that dispatch and listen to events work with any compliant event system, enabling decoupled event-driven architecture.

Common Mistakes

  • Not stopping propagation when an event has been fully handled — subsequent listeners process already-handled events.
  • Listeners that throw exceptions without considering impact on other listeners in the chain.
  • Not making event objects immutable — listeners that modify event data create hidden coupling.
  • Using PSR-14 for high-throughput events — the overhead is fine for business events, not for thousands of events per second.

Code Examples

✗ Vulnerable
// Tightly coupled event dispatch without PSR-14:
class OrderService {
    public function place(Order $o): void {
        $this->save($o);
        $this->mailer->send($o);     // Direct call — coupled
        $this->inventory->reserve($o); // Direct call — coupled
    }
}
// PSR-14: dispatch(new OrderPlaced($o)) — listeners handle independently
✓ Fixed
// PSR-14 Event Dispatcher
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\EventDispatcher\ListenerProviderInterface;

// Define an event
class OrderPlaced {
    public function __construct(
        public readonly Order $order,
        public readonly \DateTimeImmutable $placedAt = new \DateTimeImmutable(),
    ) {}
}

// Dispatch after successful order
$dispatcher->dispatch(new OrderPlaced($order));

// Register a listener
$provider->listen(OrderPlaced::class, function(OrderPlaced $event): void {
    $mailer->sendConfirmation($event->order);
});

// PSR-14 compatible: Symfony EventDispatcher, League/Event, tightenco/collect

Added 15 Mar 2026
Edited 22 Mar 2026
Views 51
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 1 ping S 0 pings S 1 ping M 2 pings T 2 pings W 1 ping T 0 pings F 1 ping S 3 pings S 1 ping M 1 ping T 1 ping W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 1 ping T 0 pings W 2 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 1 ping W
SEMrush 1
No pings yesterday
ChatGPT 20 Amazonbot 8 Google 5 Ahrefs 4 Perplexity 3 Bing 2 Scrapy 2 Claude 1 Meta AI 1 SEMrush 1
crawler 42 crawler_json 5
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Implement Psr\EventDispatcher\EventDispatcherInterface to make your event system swappable — any PSR-14 compliant dispatcher (Symfony, Laravel) can be substituted without changing event or listener code
📦 Applies To
PHP 7.2+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Custom event dispatcher not implementing PSR-14; tight coupling to framework-specific event system; no standard event interface
Auto-detectable: ✓ Yes phpstan deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update


✓ schema.org compliant