Overview
The Lyger Events system provides a robust event dispatching mechanism with support for listeners, wildcards, and broadcasting. Build decoupled applications by emitting and listening to events throughout your codebase.
Class: Lyger\Events\Event
Abstract base class for all events in your application.
Creating an Event
use Lyger\Events\Event;
class UserRegistered extends Event
{
public function __construct(
public int $userId,
public string $email,
public string $name
) {}
}
getName()
Gets the event name based on the class name.
The short class name (e.g., “UserRegistered”)
public function getName(): string
Example:
$event = new UserRegistered(123, 'john@example.com', 'John');
echo $event->getName(); // "UserRegistered"
getPayload()
Gets the event data as an array.
Array representation of the event object
public function getPayload(): array
Example:
$event = new UserRegistered(123, 'john@example.com', 'John');
$payload = $event->getPayload();
// Returns: ['userId' => 123, 'email' => 'john@example.com', 'name' => 'John']
EventDispatcher
The EventDispatcher manages event listeners and dispatches events to registered handlers.
listen()
Registers an event listener.
Event name or wildcard pattern (e.g., “User*”)
Callback function to handle the event
public static function listen(string $event, callable $listener): void
Examples:
use Lyger\Events\EventDispatcher;
// Listen to specific event
EventDispatcher::listen('UserRegistered', function($event, $payload) {
sendWelcomeEmail($event->email);
});
// Listen with wildcard
EventDispatcher::listen('User*', function($event, $payload) {
logUserActivity($event);
});
// Listen to all events
EventDispatcher::listen('*', function($event, $payload) {
logAllEvents($event->getName());
});
dispatch()
Dispatches an event to all registered listeners.
The event instance to dispatch
Array of results from all listeners
public static function dispatch(Event $event, array $payload = []): array
Example:
use Lyger\Events\EventDispatcher;
// Dispatch event
$event = new UserRegistered(123, 'john@example.com', 'John');
$results = EventDispatcher::dispatch($event);
// With additional payload
$results = EventDispatcher::dispatch($event, [
'ip_address' => '192.168.1.1',
'user_agent' => 'Mozilla/5.0...',
]);
hasListeners()
Checks if an event has any listeners.
True if event has listeners
public static function hasListeners(string $event): bool
Example:
if (EventDispatcher::hasListeners('UserRegistered')) {
echo "UserRegistered has listeners";
}
getListenerCount()
Gets the number of listeners for an event.
Number of listeners (includes wildcard matches)
public static function getListenerCount(string $event): int
Example:
$count = EventDispatcher::getListenerCount('UserRegistered');
echo "UserRegistered has {$count} listeners";
clear()
Removes all event listeners.
public static function clear(): void
Example:
// Clear all listeners (useful in testing)
EventDispatcher::clear();
clearEvent()
Removes listeners for a specific event.
public static function clearEvent(string $event): void
Example:
// Remove all UserRegistered listeners
EventDispatcher::clearEvent('UserRegistered');
Wildcard Patterns
The event system supports wildcard patterns for flexible event matching.
Pattern Matching
Exact Match
Wildcard Prefix
Wildcard Suffix
Match All
// Listen to specific event
EventDispatcher::listen('UserRegistered', function($event) {
// Only fires for UserRegistered
});
// Listen to all User events
EventDispatcher::listen('User*', function($event) {
// Fires for: UserRegistered, UserUpdated, UserDeleted
});
// Listen to all Registered events
EventDispatcher::listen('*Registered', function($event) {
// Fires for: UserRegistered, ProductRegistered
});
// Listen to all events
EventDispatcher::listen('*', function($event) {
// Fires for every event
});
Dotted Patterns:
// Listen to namespace patterns
EventDispatcher::listen('App.User.*', function($event) {
// Matches: App.User.Created, App.User.Updated
});
EventDispatcher::listen('*.Created', function($event) {
// Matches: User.Created, Product.Created, Order.Created
});
Broadcaster
The Broadcaster class enables event broadcasting to different channels.
channel()
Registers a broadcast channel.
Handler for broadcasts to this channel
public static function channel(string $name, callable $callback): void
Example:
use Lyger\Events\Broadcaster;
// Register WebSocket channel
Broadcaster::channel('websocket', function($event) {
broadcastToWebSocket($event->getName(), $event->getPayload());
});
// Register email notification channel
Broadcaster::channel('email', function($event) {
sendEmailNotification($event);
});
broadcast()
Broadcasts an event to a channel.
public static function broadcast(string $channel, Event $event): void
Example:
$event = new OrderPlaced(456, 99.99);
// Broadcast to specific channel
Broadcaster::broadcast('websocket', $event);
// Broadcast to multiple channels
Broadcaster::broadcast('email', $event);
Broadcaster::broadcast('sms', $event);
EventServiceProvider
Abstract base class for registering events and listeners in a structured way.
Creating a Service Provider
use Lyger\Events\EventServiceProvider;
use Lyger\Events\EventDispatcher;
class AppEventServiceProvider extends EventServiceProvider
{
public function register(): void
{
// Register user events
$this->listen('UserRegistered', [$this, 'sendWelcomeEmail']);
$this->listen('UserRegistered', [$this, 'createUserProfile']);
// Register order events
$this->listen('OrderPlaced', [$this, 'processPayment']);
$this->listen('OrderPlaced', [$this, 'notifyWarehouse']);
// Wildcard listeners
$this->listen('User*', [$this, 'logUserActivity']);
}
protected function sendWelcomeEmail($event): void
{
// Send email...
}
protected function createUserProfile($event): void
{
// Create profile...
}
protected function processPayment($event): void
{
// Process payment...
}
protected function notifyWarehouse($event): void
{
// Notify warehouse...
}
protected function logUserActivity($event): void
{
// Log activity...
}
}
// Bootstrap
$provider = new AppEventServiceProvider();
$provider->register();
Complete Examples
User Management System
use Lyger\Events\Event;
use Lyger\Events\EventDispatcher;
// Define events
class UserRegistered extends Event
{
public function __construct(
public int $userId,
public string $email,
public string $name
) {}
}
class UserUpdated extends Event
{
public function __construct(
public int $userId,
public array $changes
) {}
}
class UserDeleted extends Event
{
public function __construct(
public int $userId
) {}
}
// Register listeners
EventDispatcher::listen('UserRegistered', function($event) {
// Send welcome email
sendEmail($event->email, 'Welcome to our platform!');
});
EventDispatcher::listen('UserRegistered', function($event) {
// Create default profile
createProfile($event->userId);
});
EventDispatcher::listen('User*', function($event) {
// Log all user events
logActivity($event->getName(), $event->getPayload());
});
// Dispatch events
$event = new UserRegistered(123, 'john@example.com', 'John Doe');
EventDispatcher::dispatch($event);
E-commerce Order System
class OrderPlaced extends Event
{
public function __construct(
public int $orderId,
public int $userId,
public float $total,
public array $items
) {}
}
class OrderShipped extends Event
{
public function __construct(
public int $orderId,
public string $trackingNumber
) {}
}
class OrderCancelled extends Event
{
public function __construct(
public int $orderId,
public string $reason
) {}
}
// Order event handlers
EventDispatcher::listen('OrderPlaced', function($event) {
// Process payment
processPayment($event->orderId, $event->total);
});
EventDispatcher::listen('OrderPlaced', function($event) {
// Update inventory
foreach ($event->items as $item) {
decrementInventory($item['id'], $item['quantity']);
}
});
EventDispatcher::listen('OrderPlaced', function($event) {
// Send confirmation email
sendOrderConfirmation($event->userId, $event->orderId);
});
EventDispatcher::listen('OrderShipped', function($event) {
// Send tracking email
sendTrackingInfo($event->orderId, $event->trackingNumber);
});
EventDispatcher::listen('OrderCancelled', function($event) {
// Refund payment
refundPayment($event->orderId);
});
// Dispatch
$order = new OrderPlaced(789, 123, 99.99, [
['id' => 1, 'quantity' => 2],
['id' => 2, 'quantity' => 1],
]);
EventDispatcher::dispatch($order);
Application Logging System
class ErrorOccurred extends Event
{
public function __construct(
public string $message,
public string $level,
public array $context
) {}
}
class RequestReceived extends Event
{
public function __construct(
public string $method,
public string $uri,
public string $ip
) {}
}
// Global logging
EventDispatcher::listen('*', function($event) {
file_put_contents('events.log', json_encode([
'event' => $event->getName(),
'payload' => $event->getPayload(),
'time' => time(),
]) . "\n", FILE_APPEND);
});
// Error handling
EventDispatcher::listen('ErrorOccurred', function($event) {
if ($event->level === 'critical') {
notifyAdmins($event->message);
}
});
// Request logging
EventDispatcher::listen('RequestReceived', function($event) {
logRequest($event->method, $event->uri, $event->ip);
});
// Dispatch
EventDispatcher::dispatch(new ErrorOccurred(
'Database connection failed',
'critical',
['database' => 'mysql']
));
Broadcasting Example
use Lyger\Events\Broadcaster;
// Setup broadcast channels
Broadcaster::channel('websocket', function($event) {
$ws = new WebSocketClient('ws://localhost:8080');
$ws->send(json_encode([
'event' => $event->getName(),
'data' => $event->getPayload(),
]));
});
Broadcaster::channel('redis', function($event) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->publish('events', json_encode($event->getPayload()));
});
// Broadcast events
class MessageSent extends Event
{
public function __construct(
public int $userId,
public string $message
) {}
}
$event = new MessageSent(123, 'Hello World!');
// Send to WebSocket clients
Broadcaster::broadcast('websocket', $event);
// Publish to Redis
Broadcaster::broadcast('redis', $event);
Advanced Patterns
Event Queueing
class QueuedEvent extends Event
{
public function __construct(
public Event $event,
public int $delay = 0
) {}
}
EventDispatcher::listen('QueuedEvent', function($event) {
$queue = new Queue();
$queue->push($event->event, $event->delay);
});
// Usage
$userEvent = new UserRegistered(123, 'john@example.com', 'John');
EventDispatcher::dispatch(new QueuedEvent($userEvent, 60)); // Delay 60s
Conditional Listeners
EventDispatcher::listen('OrderPlaced', function($event) {
// Only notify for large orders
if ($event->total > 1000) {
notifyManager($event->orderId);
}
});
Listener Priority
// High priority listener (runs first)
EventDispatcher::listen('UserRegistered', function($event) {
validateUser($event->userId);
});
// Normal priority listeners
EventDispatcher::listen('UserRegistered', function($event) {
sendEmail($event->email);
});
Listeners are called in the order they are registered. Register critical listeners first for proper execution order.
Best Practices
- Event Naming: Use past tense for event names (e.g.,
UserRegistered not UserRegister)
- Immutability: Make event properties readonly to prevent modification
- Payload Size: Keep event payloads small - include IDs, not entire objects
- Error Handling: Wrap listener code in try-catch to prevent cascade failures
- Testing: Use
EventDispatcher::clear() between tests to avoid listener pollution
// Good event design
class UserRegistered extends Event
{
public function __construct(
public readonly int $userId, // ID only
public readonly string $email // Essential data
) {}
}
// Listeners handle their own errors
EventDispatcher::listen('UserRegistered', function($event) {
try {
sendWelcomeEmail($event->email);
} catch (\Exception $e) {
logError($e->getMessage());
}
});