直接实现 splobserver 容易失效,因 splsubject 不自动调用 notify() 且 attach() 对非 splobserver 对象静默跳过;必须严格实现接口、手动管理观察者数组并确保 update() 参数为 splsubject 类型。

为什么直接实现 SplObserver 容易失效
因为 SplSubject 不会自动调用 notify(),你得手动触发;而且 attach() 时如果传入的不是实现了 SplObserver 的对象,PHP 不报错但后续 notify() 会静默跳过——这是最常被忽略的“没反应”原因。
典型错误现象:update() 方法压根不执行,调试发现 notify() 被调了,但观察者列表为空或类型不匹配。
- 必须确保观察者类明确
implements SplObserver,不能只写个同名方法 -
SplSubject子类里要自己维护$observers数组,并在attach()/detach()中操作它 -
notify()必须显式遍历并调用每个观察者的update($subject)
一个能跑通的最小 SplSubject 实现
别依赖第三方库,先写一个可验证的基类。关键点是:attach() 做类型检查,notify() 保证参数传递正确。
class EventSubject implements SplSubject {
private array $observers = [];
public function attach(SplObserver $observer): void {
$this->observers[] = $observer;
}
public function detach(SplObserver $observer): void {
$key = array_search($observer, $this->observers, true);
if ($key !== false) unset($this->observers[$key]);
}
public function notify(): void {
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
注意:update() 的参数必须是 SplSubject 类型(即当前实例),否则观察者接收不到上下文。
观察者必须严格实现 SplObserver 接口
常见错误是把 update() 写成 onEvent() 或漏掉参数类型声明。PHP 7.4+ 会因类型不匹配拒绝注册,但低版本可能只在运行时报错或静默失败。
- 接口强制要求方法签名是
update(SplSubject $subject),不能少参数、不能改类型 - 如果需要传额外数据(如事件名、payload),必须通过
$subject的属性或方法暴露,比如加一个getData()方法 - 多个观察者可以共用同一个类,靠
$subject区分状态,不必为每个事件建新类
示例观察者:
class LogObserver implements SplObserver {
public function update(SplSubject $subject): void {
echo "Log: subject changed at " . date('Y-m-d H:i:s') . "\n";
}
}
实际联动中容易卡住的兼容性细节
SplSubject 和 SplObserver 是 PHP 标准库的一部分,但它们不支持构造时传参、不支持优先级排序、也不提供事件名称过滤——这意味着你要自己扩展。
- 想按事件类型通知?给
EventSubject加个$event属性和notifyEvent(string $name)方法 - 想异步或延迟通知?不能直接在
notify()里起协程,需配合Swoole\Coroutine或队列,原生 SPL 不处理这个 - PHP 8.2+ 已标记
SplSubject为废弃(@deprecated),虽暂未移除,但新项目建议用普通接口 + 手动管理,避免未来升级踩坑
真正难的不是写对两个接口,而是让不同模块的观察者能拿到彼此需要的数据结构,而不是反复 cast 或访问私有属性。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











