sabre/event
Lightweight PHP 8.2+ library for event-driven development: EventEmitter, promises, an event loop, and coroutines. Used to build reactive, non-blocking apps and services. Full docs at sabre.io/event.
EventEmitter and Promise-based architecture aligns with Laravel’s event system but extends it with async primitives (Event Loop, Coroutines). Ideal for non-HTTP async workflows (e.g., WebSocket servers, CLI workers) where Laravel’s synchronous Bus or Events are insufficient..then(), .catch()) while leveraging PHP’s Event Loop for non-blocking execution. Overlaps with Laravel’s PendingDispatch but offers lower-level control.Sabre\Event\coroutine) enable cooperative multitasking, useful for stateful async workflows (e.g., polling APIs with backoff).WildcardEmitter allows dynamic event routing (e.g., user.*), useful for plugin architectures or dynamic event handling.EventLoop can block Laravel’s request lifecycle. Use only in Artisan commands, queues, or custom workers.EventLoop::run() in a custom command).Emitter/EventLoop manually (no Laravel service container integration).illuminate/support).| Risk Area | Assessment | Mitigation Strategy |
|---|---|---|
| PHP 8.2+ Dependency | Breaks compatibility with Laravel <10 (PHP 8.1) or legacy stacks. | Phase adoption: Start with v6.0.x (PHP 7.4–8.1) for legacy; migrate to v6.1.0 for new features. |
| Event Loop Blocking | Running EventLoop::run() in HTTP context freezes requests. |
Restrict usage to CLI/Artisan; use Laravel queues for HTTP async tasks. |
| Promise API Changes | BC breaks in v6.0+ (e.g., Promise::error → Promise::otherwise). |
Audit existing Promise usage; update to v6.1.0’s strict typing. |
| Coroutine Complexity | Generators/coroutines add debugging overhead (stack traces, state management). | Limit scope to experimental features; document usage patterns. |
| Lack of Laravel Binds | No native integration with Laravel’s Event facade or Bus. |
Wrap Emitter in a custom facade or service class for Laravel consistency. |
| Performance Overhead | Event Loop may introduce latency vs. synchronous code or queues. | Benchmark against ReactPHP or Laravel queues; reserve for high-throughput async. |
Use Case Clarity:
Bus/Events or ReactPHP?
yield-based backoff).Adoption Strategy:
Team Readiness:
yield vs. return in generators).Long-Term Support:
Swoole/RoadRunner integration).Alternatives:
| Laravel Component | Sabre/Event Fit | Integration Notes |
|---|---|---|
| HTTP Requests | ❌ Avoid | EventLoop blocks requests. Use Laravel queues or Swoole instead. |
| Artisan Commands | ✅ Excellent | Ideal for CLI async workflows (e.g., php artisan event:loop). Instantiate EventLoop in a command. |
| Queues | ✅ Partial | Use for non-blocking queue workers (e.g., EventLoop::run() in HandleJobs). Avoid mixing with Laravel’s Bus. |
| Events | ✅ Complementary | Replace custom event emitters with Sabre\Event\Emitter for decoupled async logic. Bridge to Laravel’s Event facade via a wrapper class. |
| WebSockets | ✅ Target Use Case | Pair with Laravel Echo or Ratchet for real-time async handlers. Sabre/Event manages event dispatch while WebSocket lib handles I/O. |
| APIs/CLI Tools | ✅ High Value | Replace synchronous loops with EventLoop + Coroutines (e.g., polling APIs with yield-based delays). |
| Plugins/Microservices | ✅ Wildcard Listeners | Use WildcardEmitter for dynamic event routing (e.g., plugin.{name}.event). |
Assess PHP Version:
Pilot Integration:
composer.json:
composer require sabre/event "^6.1" --dev # Start with dev dependency
use Sabre\Event\EventEmitter;
use Sabre\Event\EventLoop;
// Example: Async CLI task
$emitter = new EventEmitter();
$loop = new EventLoop();
$emitter->on('task.complete', fn() => echo "Done!\n");
$loop->run(); // Blocks until events are emitted
Laravel-Specific Setup:
$this->app->singleton('sabre.emitter', fn() => new EventEmitter());
// app/Facades/SabreEmitter.php
public static function emit(string $event, $data = null) {
return app('sabre.emitter')->emit($event, $data);
}
Event Loop Isolation:
// ❌ BAD: Blocks the entire request
route('async', fn() => EventLoop::run());
// ✅ GOOD: Use in Artisan or queues
EventLoop::run
How can I help you explore Laravel packages today?