PSR-14: Event Dispatcher
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
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
17
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
Amazonbot 8
Perplexity 3
Google 3
Ahrefs 2
ChatGPT 2
Also referenced
How they use it
crawler 15
crawler_json 3
Related categories
⚡
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