psr/event-dispatcher
PSR-14 interfaces for event dispatching in PHP. Defines standard contracts for dispatchers, listeners, and providers to enable interoperability between frameworks and libraries. Not an implementation—use a compatible PSR-14 dispatcher package.
Install the package via Composer:
composer require psr/event-dispatcher
⚠️ This package contains only interfaces—no runtime logic. To actually dispatch or listen for events, install a PSR-14-compliant implementation:
Event::getFacadeRoot() already implements EventDispatcherInterface.symfony/event-dispatcher (v5.1+) provides EventDispatcher implementing PSR-14.symfony/event-dispatcher or ocramius/event-dispatcher.Your first real step: define a simple event class (e.g., UserCreatedEvent) and a listener, then inject Psr\EventDispatcher\EventDispatcherInterface into a service and call $dispatcher->dispatch(new UserCreatedEvent()).
Standard Dispatching Workflow:
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\EventDispatcher\StoppableEventInterface;
class UserCreatedEvent implements StoppableEventInterface {
public function isPropagationStopped(): bool { return false; }
}
class NotifyAdminListener {
public function __invoke(UserCreatedEvent $event): void { /* ... */ }
}
// In a controller/service
public function __construct(private EventDispatcherInterface $dispatcher) {}
$this->dispatcher->dispatch(new UserCreatedEvent());
Listener Auto-Registration with Laravel:
Laravel’s EventServiceProvider can coexist with PSR-14. Register PSR-14 listeners alongside Laravel-style listeners in EventServiceProvider—use Event::listen() for legacy events, and dispatch() with PSR-14 types for new events.
Advanced Listener Management:
Implement Psr\EventDispatcher\ListenerProviderInterface to power dynamic or context-aware listeners (e.g., loading listeners from config or DB at runtime). Example:
class ConfiguredListenerProvider implements ListenerProviderInterface {
public function getListenersForEvent(object $event): iterable {
return match($event::class) {
UserCreatedEvent::class => [new NotifyAdminListener()],
default => [],
};
}
}
Interoperability Layer:
Type-hint against PSR-14 interfaces in shared packages or bundles to ensure they work in any framework—whether Symfony, Laravel, or custom. Avoid framework-specific contracts like Illuminate\Contracts\Events\Dispatcher.
❗ Critical gotcha: Installing psr/event-dispatcher alone won’t make events work—you’ll get Error: Class 'Psr\EventDispatcher\EventDispatcherInterface' not found at runtime if no implementation is available. Always check composer show psr/event-dispatcher-implementation to verify an implementation is installed.
✅ Debugging tip: Wrap your dispatcher in Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher during development:
$traceable = new TraceableEventDispatcher($dispatcher, $logger);
// Dispatch via $traceable to see full propagation trace
🔍 Laravel nuance: Event::listen() does not register PSR-14 listeners. Use app(EventDispatcherInterface::class)->dispatch() directly, or alias Laravel’s dispatcher via Event::getFacadeRoot() (which is PSR-14 compatible in Laravel 8+).
🧠 Design pattern tip: Use Psr\EventDispatcher\IdentifiesEvent (via class name match) to write generic listeners that handle multiple event types cleanly:
class GenericAuditListener {
public function __invoke(object $event): void {
$eventName = $event instanceof IdentifiesEvent ? $event->getEventName() : $event::class;
// Log with consistent event key
}
}
⚙️ Performance optimization: Implement ListenerProviderInterface lazily (e.g., using a DI container’s make() inside getListenersForEvent) to avoid loading unused listeners—especially in high-traffic apps.
How can I help you explore Laravel packages today?