phpnomad/event provides interfaces for event-driven architecture in PHP applications. Components broadcast events when something happens, and listeners react without the publisher needing to know who is listening. That lets you add behavior like sending a welcome email, updating a cache, or writing an audit log by writing a new handler instead of modifying existing code.
This package is interfaces only. It has zero runtime dependencies and it does not ship a dispatcher. For a working event system you also install a concrete implementation. The recommended one is phpnomad/symfony-event-dispatcher-integration, which adapts Symfony's EventDispatcher to the EventStrategy contract. The package is used in production by Siren and by every PHPNomad package that needs to broadcast or listen for events.
composer require phpnomad/eventFor a working dispatcher, also install the Symfony integration:
composer require phpnomad/symfony-event-dispatcher-integrationDefine an event. It just needs a stable identifier and whatever payload you want handlers to see.
usePHPNomad\Events\Interfaces\Event;
class UserCreatedEvent implements Event
{
publicfunction__construct(
publicreadonlyint$userId,
publicreadonlystring$email
) {}
publicstaticfunctiongetId(): string
{
return'user.created';
}
}Write a handler that reacts to the event.
usePHPNomad\Events\Interfaces\CanHandle;
usePHPNomad\Events\Interfaces\Event;
class SendWelcomeEmailHandler implements CanHandle
{
publicfunction__construct(privateEmailService$email) {}
publicfunctionhandle(Event$event): void
{
$this->email->send($event->email, 'Welcome!');
}
}Declare the event-to-handler mapping on a module so the bootstrapper can wire it up.
usePHPNomad\Events\Interfaces\HasListeners;
class UserModule implements HasListeners
{
publicfunctiongetListeners(): array
{
return [
UserCreatedEvent::class => SendWelcomeEmailHandler::class,
];
}
}Broadcast the event from wherever the state change actually happens.
usePHPNomad\Events\Interfaces\EventStrategy;
class UserService
{
publicfunction__construct(privateEventStrategy$events) {}
publicfunctioncreateUser(string$email): User
{
$user = newUser($email);
// persist the user...$this->events->broadcast(newUserCreatedEvent(
userId: $user->getId(),
email: $user->getEmail()
));
return$user;
}
}The UserService has no knowledge of SendWelcomeEmailHandler. Adding a second handler for logging, analytics, or a Slack notification is a new class and one extra line in getListeners(). The service code does not change.
Event: an object representing something that happened, identified by a staticgetId()stringEventStrategy: the dispatcher interface withbroadcast(),attach(), anddetach()CanHandle: the contract a handler implements to react to an eventHasListeners: modules implement this to declare their event-to-handler mappingsHasEventBindings: flexible binding configuration for platform integration layersActionBindingStrategy: bridges external systems like WordPress hooks into application events
Full documentation, including the interface reference and event design best practices, lives at phpnomad.com.
MIT. See LICENSE.txt.