hyperf/event
hyperf/event is a lightweight event dispatcher for Hyperf applications. Define events and listeners, dispatch synchronously or via async mechanisms, and keep your domain decoupled. Integrates cleanly with Hyperf’s DI and coroutine-friendly runtime.
Installation:
composer require hyperf/event
Ensure the package is auto-loaded in composer.json or manually register in config/autoload.php:
'dependencies' => [
Hyperf\Event\EventDispatcher::class,
],
Define an Event:
Create a class implementing Hyperf\Event\Contract\EventInterface (or extend Hyperf\Event\Event):
namespace App\Events;
use Hyperf\Event\Event;
class OrderCreated extends Event
{
public function __construct(public int $orderId, public array $data) {}
}
Dispatch an Event:
Inject EventDispatcher and dispatch:
use Hyperf\Event\EventDispatcher;
class OrderController
{
public function __construct(private EventDispatcher $dispatcher) {}
public function createOrder()
{
$this->dispatcher->dispatch(new OrderCreated(123, ['items' => []]));
}
}
Register a Listener:
Define a listener class implementing Hyperf\Event\Contract\ListenerInterface:
namespace App\Listeners;
use App\Events\OrderCreated;
use Hyperf\Event\Contract\ListenerInterface;
class SendOrderConfirmation implements ListenerInterface
{
public function handle(OrderCreated $event)
{
// Logic to send confirmation
}
}
Configure Listeners:
Bind listeners in config/autoload/event.php:
return [
'listen' => [
OrderCreated::class => [
\App\Listeners\SendOrderConfirmation::class,
],
],
];
Dispatch an event to trigger background tasks (e.g., sending emails, updating analytics) without blocking the request:
// Dispatch
$this->dispatcher->dispatch(new UserRegistered($userId));
// Listener (runs in background via Swoole coroutines)
class HandleUserRegistration implements ListenerInterface
{
public function handle(UserRegistered $event)
{
go(function () use ($event) {
// Non-blocking email sending
sendWelcomeEmail($event->userId);
});
}
}
Decouple Components: Use events to communicate between services (e.g., PaymentProcessed → InventoryUpdate).
// Dispatch payment event
$this->dispatcher->dispatch(new PaymentProcessed($orderId, $amount));
// Listener for inventory
class UpdateInventory implements ListenerInterface
{
public function handle(PaymentProcessed $event)
{
reduceInventory($event->orderId, $event->amount);
}
}
Fan-Out Pattern: Broadcast events to multiple listeners:
// config/autoload/event.php
return [
'listen' => [
PaymentProcessed::class => [
UpdateInventory::class,
SendReceipt::class,
LogPayment::class,
],
],
];
Attach middleware to events for cross-cutting concerns (e.g., logging, auth):
// Define middleware
class LogEventMiddleware
{
public function __invoke($event, $next)
{
\Log::info("Event dispatched: " . get_class($event));
return $next($event);
}
}
// Apply middleware to an event
$this->dispatcher->dispatchWithMiddleware(
new OrderCreated(123, []),
[LogEventMiddleware::class]
);
Route events dynamically based on conditions (e.g., tenant ID):
// In a service or controller
$event = new OrderCreated(123, ['tenant_id' => 'acme']);
$this->dispatcher->route($event, 'tenant_' . $event->data['tenant_id']);
Broadcast events to WebSocket clients:
// Define a WebSocket event
class OrderUpdated extends Event
{
public function broadcastOn(): string
{
return 'private-order.' . $this->orderId;
}
}
// Listener to push to WebSocket
class BroadcastOrderUpdate implements ListenerInterface
{
public function handle(OrderUpdated $event)
{
$this->dispatcher->dispatch(new WebSocketEvent(
$event->broadcastOn(),
$event
));
}
}
Use priority queues for time-sensitive events:
// Dispatch with priority
$this->dispatcher->dispatchWithPriority(
new HighPriorityEvent(),
'high'
);
// Configure priority listeners
return [
'listen' => [
HighPriorityEvent::class => [
['\App\Listeners\ProcessUrgentTask', 'high'],
],
],
];
Bridge Laravel events to Hyperf (if migrating or using both):
// Configure in config/autoload/event.php
return [
'adapters' => [
'laravel' => [
'enabled' => true,
'fallback_to_redis' => env('FALLBACK_TO_REDIS', false),
],
],
];
// Dispatch a Laravel event (auto-converted)
event(new \App\Events\LaravelEvent());
Leverage Swoole coroutines for non-blocking listeners:
class AsyncTaskListener implements ListenerInterface
{
public function handle(Event $event)
{
go(function () use ($event) {
// Non-blocking I/O (e.g., HTTP requests, DB writes)
$result = \Http::post('https://api.example.com', $event->data);
\Log::info("Async task completed: " . $result);
});
}
}
Filter events before dispatching (e.g., validate payloads):
// Middleware to filter events
class ValidateEventPayload
{
public function __invoke($event, $next)
{
if (!isset($event->data['required_field'])) {
throw new \InvalidArgumentException("Missing required field");
}
return $next($event);
}
}
// Apply to all events
$this->dispatcher->pipe(ValidateEventPayload::class);
Blocking Listeners:
file_get_contents, DB::table()->get()) in listeners. Use coroutines (go) or async methods.go:
go(function () {
$data = \Http::get('https://api.example.com');
});
Event Ordering:
EventTransaction for critical paths:
use Hyperf\Event\EventTransaction;
$transaction = new EventTransaction();
$transaction->dispatch(new EventA());
$transaction->dispatch(new EventB());
$transaction->commit();
Memory Leaks:
WebSocket Payload Size:
EventWebSocket logs for truncation warnings.Laravel Adapter Quirks:
ShouldBroadcastNow). Test thoroughly.EventWebSocket for broadcasting instead of Laravel’s ShouldBroadcast.Priority Misconfiguration:
config/autoload/event.php:
'priorities' => ['low', 'normal', 'high', 'critical'],
Coroutine Deadlocks:
yield usage can cause deadlocks.$result = yield \Swoole\Coroutine::create(function () {
return \Http::get('https://api.example.com', ['timeout' => 2]);
});
Enable Event Logging:
// config/autoload/event.php
'debug' => true,
Logs dispatched events and listeners to storage/logs/hyperf.log.
Trace Events:
Use the hyperf:event:trace CLI tool to trace event flows:
php bin/hyperf.php event:trace OrderCreated
Monitor WebSocket Connections: Check active WebSocket connections:
php bin/hyperf.php webs
How can I help you explore Laravel packages today?