pub struct EventDispatcher { /* private fields */ }Expand description
事件分发器(对齐 PHP think\Event)
对齐 PHP think\Event 类(272 行),提供事件监听/触发/订阅/观察者全 API。
§线程安全
内部用 Arc<RwLock<>> 保护 listener 和 bind 映射,允许并发读写。
Listener 要求 Send + Sync,可在多线程环境中分发事件。
§PHP 行为对齐
- 事件别名(bind):
listen('AppInit', ...)实际注册到event\AppInit::class - 优先执行(first):
listen(event, listener, true)用array_unshift插入队首 - 触发返回值:
trigger返回所有监听器返回值数组;once=true返回首个非 null - false 停止:监听器返回
false时停止后续监听器执行 - once 停止:
once=true时监听器返回非 null 值停止后续 - 点号通配:
trigger('User.login')同时触发User.login和User.*监听器 - array_unique:
trigger对监听器列表去重(SORT_REGULAR)
Implementations§
Source§impl EventDispatcher
impl EventDispatcher
Sourcepub fn new() -> EventDispatcher
pub fn new() -> EventDispatcher
创建新的事件分发器(对齐 PHP __construct(App $app),Rust 无需 App 容器)
Sourcepub fn listen_events(
&self,
events: Vec<(String, Vec<Arc<dyn Listener>>)>,
) -> &EventDispatcher
pub fn listen_events( &self, events: Vec<(String, Vec<Arc<dyn Listener>>)>, ) -> &EventDispatcher
批量注册事件监听(对齐 PHP listenEvents(array $events))
PHP:
Event::listenEvents([
'UserLogin' => [LoginListener1::class, LoginListener2::class],
'UserLogout' => [LogoutListener::class],
]);Rust:
dispatcher.listen_events(vec![
("UserLogin".to_string(), vec![Arc::new(LoginListener1), Arc::new(LoginListener2)]),
("UserLogout".to_string(), vec![Arc::new(LogoutListener)]),
]);Sourcepub fn listen(
&self,
event: &str,
listener: Arc<dyn Listener>,
first: bool,
) -> &EventDispatcher
pub fn listen( &self, event: &str, listener: Arc<dyn Listener>, first: bool, ) -> &EventDispatcher
注册事件监听(对齐 PHP listen(string $event, $listener, bool $first = false))
PHP:
Event::listen('UserLogin', function($params) { ... });
Event::listen('UserLogin', UserLoginListener::class);
Event::listen('UserLogin', [UserLoginListener::class, 'handle'], true); // 优先执行Rust:
dispatcher.listen("UserLogin", Arc::new(ClosureListener::new(|_| Ok(Value::Null))), false);
dispatcher.listen("UserLogin", Arc::new(UserLoginListener), true); // 优先执行PHP 行为对齐:
first=true时插入队首(array_unshift)first=false时追加队尾($this->listener[$event][])- 应用事件别名(
bind映射)
Sourcepub fn has_listener(&self, event: &str) -> bool
pub fn has_listener(&self, event: &str) -> bool
是否存在事件监听(对齐 PHP hasListener(string $event): bool)
Sourcepub fn bind(&self, events: Vec<(String, String)>) -> &EventDispatcher
pub fn bind(&self, events: Vec<(String, String)>) -> &EventDispatcher
指定事件别名标识(对齐 PHP bind(array $events))
PHP:
Event::bind([
'UserLogin' => 'app\event\UserLogin',
]);Rust:
dispatcher.bind(vec![("UserLogin".to_string(), "app\\event\\UserLogin".to_string())]);Sourcepub fn subscribe(&self, subscriber: Arc<dyn Subscriber>) -> &EventDispatcher
pub fn subscribe(&self, subscriber: Arc<dyn Subscriber>) -> &EventDispatcher
注册事件订阅者(对齐 PHP subscribe($subscriber))
PHP:
Event::subscribe(UserEventSubscriber::class);
// 或
Event::subscribe(new UserEventSubscriber());Rust:
dispatcher.subscribe(Arc::new(UserEventSubscriber));PHP 行为对齐:
- 若订阅者有
subscribe方法 → 手动订阅(调用$subscriber->subscribe($this)) - 否则 → 智能订阅(调用
observe($subscriber))
Rust 端统一通过 Subscriber trait 的 subscribe 方法手动订阅。
若需智能订阅,用 observe 方法。
Sourcepub fn observe(
&self,
observer: Arc<dyn Observer>,
prefix: &str,
) -> &EventDispatcher
pub fn observe( &self, observer: Arc<dyn Observer>, prefix: &str, ) -> &EventDispatcher
自动注册事件观察者(对齐 PHP observe($observer, string $prefix = ''))
PHP:
Event::observe(new UserObserver());
// 自动注册 UserObserver 的 onLogin() → 'Login' 事件Rust:
dispatcher.observe(Arc::new(UserObserver), "");PHP 行为对齐:
- 反射获取所有
onXxx公开方法 - 注册
listen($prefix . $event_name, [$observer, 'on' . $event_name]) - 若有
eventPrefix属性,用作前缀
Rust 端通过 Observer trait 的 events() 方法声明事件映射,
避免运行时反射(Rust 无反射)。
Sourcepub fn trigger(
&self,
event: &str,
params: &Value,
once: bool,
) -> Result<Vec<Value>, EventError>
pub fn trigger( &self, event: &str, params: &Value, once: bool, ) -> Result<Vec<Value>, EventError>
触发事件(对齐 PHP trigger($event, $params = null, bool $once = false))
PHP:
$results = Event::trigger('UserLogin', ['user_id' => 123]);
$first = Event::trigger('UserLogin', ['user_id' => 123], true); // 只获取一个有效返回值Rust:
let results = dispatcher.trigger("UserLogin", &json!({"user_id": 123}), false).unwrap();
let first = dispatcher.trigger("UserLogin", &json!({"user_id": 123}), true).unwrap();PHP 行为对齐:
- 若
$event是对象,取类名作为事件名,对象作为参数 - 应用事件别名(
bind映射) - 点号通配:
User.login同时触发User.login和User.* array_unique对监听器去重- 逐个调用
dispatch,返回值收集到$result - 监听器返回
false→ 停止后续 once=true且监听器返回非 null → 停止后续once=false返回所有返回值数组;once=true返回最后一个非 null 返回值
Sourcepub fn trigger_spawn(
&self,
event: &str,
params: &Value,
) -> Vec<JoinHandle<Result<Value, EventError>>>
pub fn trigger_spawn( &self, event: &str, params: &Value, ) -> Vec<JoinHandle<Result<Value, EventError>>>
异步触发事件 — fire-and-forget(Rust 特有扩展,对齐 think-swoole 异步事件分发)
每个监听器在独立的 tokio::task 中并发执行,立即返回 JoinHandle 列表不等待。
适用于非关键事件(日志、指标、通知),不阻塞当前请求。
注意:必须在 tokio 运行时中调用(axum 服务器已提供运行时)。
调用方可选择 .await JoinHandle 获取结果,或丢弃 JoinHandle 实现 fire-and-forget。
与同步 trigger 的差异:
- 同步
trigger:逐个串行执行,支持once/false停止 - 异步
trigger_spawn:并发执行,不支持once/false停止(各监听器独立运行) - 两者的 bind 别名 / 点号通配 / 去重逻辑完全一致(共用
collect_listeners)
Rust:
// fire-and-forget(丢弃 JoinHandle)
dispatcher.trigger_spawn("UserLogin", &json!({"user_id": 123}));
// 等待所有监听器完成
let handles = dispatcher.trigger_spawn("UserLogin", &json!({"user_id": 123}));
for handle in handles {
let _ = handle.await;
}Sourcepub async fn trigger_async(
&self,
event: &str,
params: &Value,
) -> Vec<Result<Value, EventError>>
pub async fn trigger_async( &self, event: &str, params: &Value, ) -> Vec<Result<Value, EventError>>
异步触发事件并等待所有监听器完成(Rust 特有扩展,对齐 think-swoole 异步事件分发)
等价于 trigger_spawn + 逐个 .await,返回所有监听器的结果列表。
监听器错误被收集到 Vec 中(不传播),包括 task panic 产生的 JoinError。
注意:必须在 tokio 运行时中调用。监听器并发执行,结果顺序与注册顺序一致
(因为 trigger_spawn 返回的 JoinHandle 列表保持注册顺序)。
Rust:
let results = dispatcher.trigger_async("UserLogin", &json!({"user_id": 123})).await;
for result in &results {
if let Err(e) = result {
eprintln!("Listener error: {}", e);
}
}Sourcepub fn until(
&self,
event: &str,
params: &Value,
) -> Result<Vec<Value>, EventError>
pub fn until( &self, event: &str, params: &Value, ) -> Result<Vec<Value>, EventError>
触发事件(只获取一个有效返回值)(对齐 PHP until($event, $params = null))
等价 trigger(event, params, true),返回最后一个非 null 返回值。
Sourcepub fn listener_count(&self, event: &str) -> usize
pub fn listener_count(&self, event: &str) -> usize
获取事件的所有监听器数量(PHP 无对应 API,Rust 扩展用于测试)
Trait Implementations§
Source§impl Default for EventDispatcher
impl Default for EventDispatcher
Source§fn default() -> EventDispatcher
fn default() -> EventDispatcher
Auto Trait Implementations§
impl !Freeze for EventDispatcher
impl RefUnwindSafe for EventDispatcher
impl Send for EventDispatcher
impl Sync for EventDispatcher
impl Unpin for EventDispatcher
impl UnsafeUnpin for EventDispatcher
impl UnwindSafe for EventDispatcher
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.