fiberphp / event
FiberPHP event dispatcher: supports exact name and prefix wildcard listeners, emit/dispatch dual mode.
dev-master
2026-08-22 10:23 UTC
Requires
- php: >=8.3
- fiberphp/framework: dev-master
Requires (Dev)
- fiberphp/log: dev-master
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-08-22 10:24:04 UTC
README
FiberPHP 框架的事件子包。提供轻量级事件分发器,支持精确事件名匹配与通配符前缀匹配,emit(异常安全)与 dispatch(异常传播)双模式触发,通过 config/event.php 声明式注册监听器,由 EventProvider 在 Worker 启动时统一加载。
特性
- 精确匹配:
Event::on('user.login', $cb)注册,Event::emit('user.login', $data)触发。 - 通配符前缀:
Event::on('user.*', $cb)匹配所有以user.开头的事件。 - 双模式触发:
emit捕获异常并记录日志、不中断后续监听器;dispatch直接抛出异常。 - halt 模式:首个非
null响应后停止,支持事件链短路。 - false 中断:监听器返回
false时中断后续监听器执行。 - 声明式注册:
config/event.php配置监听器,支持闭包、类方法、多监听器优先级排序。 - 容器解析:
['ClassName', 'method']格式的监听器自动通过容器解析实例。 - CLI 诊断:
event:list命令列出全部已注册的监听器。
环境要求
- PHP >= 8.3
fiberphp/frameworkdev-masterfiberphp/logdev-master(可选,未安装时回退 framework 兜底 Logger)
安装
composer require fiberphp/event
安装后 PackageInstaller::discover 会自动把 config/event.php 拷贝到应用 config/event.php(幂等,已存在不覆盖),并通过 PackageManifest 注册 EventProvider,无需手动配置。
配置
config/event.php:
return [
// 是否启用事件监听器注册
'enable' => true,
// 事件监听器配置
// key 为事件名,value 为监听器(支持单个或多个)
// 监听器格式:
// - 闭包: fn($data, $event) => ...
// - 类方法: [ClassName::class, 'method'] (类通过容器解析)
// - 多个监听器: ['key1' => listener, 'key2' => listener, ...] (按 key 自然排序执行)
//
// 通配符前缀:以 "*" 结尾的事件名匹配前缀,如 'user.*' 匹配 'user.login'、'user.logout' 等
'user.registered' => [
[\App\Listener\EmailListener::class, 'onUserRegistered'],
[\App\Listener\SmsListener::class, 'onUserRegistered'],
],
'user.*' => fn($data, $event) => logger()->info("用户事件: {$event}", $data),
'order.paid' => [\App\Listener\OrderListener::class, 'onOrderPaid'],
];
监听器格式说明:
| 格式 | 示例 | 说明 |
|---|---|---|
| 闭包 | fn($data, $event) => ... | 直接可调用的闭包 |
| 类方法 | [ClassName::class, 'method'] | 类通过容器解析为单例,调用 method |
| 多监听器 | ['a' => $cb1, 'b' => $cb2] | 数字键按 ksort 自然排序依次执行 |
使用
基本调用
// framework 全局 helper(推荐)
event(); // 返回 Event 管理器实例
// 注册监听器
Event::on('user.login', function ($data, $event) {
logger()->info("用户登录: {$event}", $data);
});
// 触发事件
Event::emit('user.login', ['user_id' => 123]);
// 派发事件(异常直接抛出)
Event::dispatch('order.paid', ['order_id' => 456]);
通配符前缀
// 匹配所有 user.* 事件
Event::on('user.*', function ($data, $event) {
logger()->info("用户事件: {$event}", $data);
});
Event::emit('user.login', $data); // 触发
Event::emit('user.logout', $data); // 触发
Event::emit('order.create', $data); // 不触发
halt 模式
// 首个非 null 响应后停止
$result = Event::emit('cache.get', $key, halt: true);
if ($result !== null) {
return $result; // 命中缓存
}
false 中断
// 返回 false 中断后续监听器
Event::on('auth.check', fn() => false); // 中断
Event::on('auth.check', fn() => true); // 不会执行
移除监听器
// on() 返回监听器 ID,用于精确移除
$id = Event::on('user.login', $cb);
Event::off('user.login', $id); // 精确事件移除
Event::off('user.*', $id); // 通配符移除
查询监听器
// 是否存在监听器
Event::hasListener('user.login'); // true
Event::hasListener('user.logout'); // 通配符 user.* 也会命中
// 获取全部监听器(含前缀匹配)
$listeners = Event::getListeners('user.login');
// 列出全部已注册的监听器(返回 [id => [event_name, callable], ...])
foreach (Event::list() as $id => [$eventName, $callback]) {
// ...
}
emit vs dispatch
| 项 | emit | dispatch |
|---|---|---|
| 异常处理 | 捕获并记录日志,继续执行后续监听器 | 直接抛出,中断后续监听器 |
| 适用场景 | 通知型事件(日志、缓存、统计) | 约束型事件(权限、事务、验证) |
| 返回值 | 全部响应数组(halt 模式除外) | 全部响应数组(halt 模式除外) |
CLI 诊断
php start.php event:list
输出表格列出所有已注册的事件监听器(ID、事件名、回调类型)。
License
MIT