PHP 8.4 不提供观察者模式运行时支持,SplSubject/SplObserver 仅为类型提示空接口,需手动实现全部逻辑;accessor 与事件无关,不可在 set: 中调用 notify()。

PHP 8.4 本身不提供内置的观察者模式运行时支持,也没有新增 SplSubject/SplObserver 的语法糖或自动绑定机制。它引入的 get:/set: accessors 是属性级封装工具,和事件通知无关——别把 accessor 当成 observer。
PHP 8.4 中观察者模式仍是手动实现
你得自己定义接口、维护观察者列表、触发通知。PHP 原生的 SplSubject 和 SplObserver 接口依然可用,但它们是空壳(没有方法签名),仅作类型提示用途,实际逻辑全靠你自己写。
-
SplSubject::attach()和SplSubject::notify()都是空方法,不强制实现任何行为 - 如果你用
implements SplSubject,必须手动补全全部逻辑,框架不会帮你注册或调用 - PHP 8.4 没有修改这一设计;它专注的是语言层语法(如 accessors、pattern matching),不是运行时事件模型
用 SplSubject/SplObserver 写一个最小可运行观察者
下面这段代码在 PHP 8.4 下完全有效,且符合原生接口约定:
<?php
class NewsSubject implements SplSubject {
private array $observers = [];
private string $headline = '';
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);
}
}
public function setHeadline(string $h): void {
$this->headline = $h;
$this->notify(); // 主动触发
}
public function getHeadline(): string {
return $this->headline;
}
}
class EmailObserver implements SplObserver {
public function update(SplSubject $subject): void {
echo 'Email sent: ' . $subject->getHeadline() . "\n";
}
}
$news = new NewsSubject();
$news->attach(new EmailObserver());
$news->setHeadline('PHP 8.4 released');
// 输出:Email sent: PHP 8.4 released
注意:update() 方法接收的是 SplSubject 实例,不是原始数据;你要从 subject 上主动取值,不能依赖传参带 payload。
立即学习“PHP免费学习笔记(深入)”;
TP8.0 或 Laravel 风格事件不等于 PHP 原生观察者
很多人混淆了“框架事件系统”和“设计模式实现”。ThinkPHP 8.0 的 model.before_write 是基于其内部 event() 调度器的字符串事件总线,和 SplSubject 没有任何继承或兼容关系。
- TP8.0 不识别
SplObserver,也不调用它的update() -
event()->listen('model.before_write', [...])是框架自己的注册方式,与观察者模式“形似神不似” - 如果你在 TP8.0 里想用观察者模式,得自己 new 类、自己 attach,不能指望框架自动注入或触发
真正该警惕的坑:accessor 不能替代事件监听
有人试图在 PHP 8.4 的 set: 里触发 notify(),比如:
private string $status set: $this->value = $value; $this->notify(); // ❌ 错误!
这会导致严重问题:
- 属性赋值发生在构造函数或普通赋值语句中,此时
$this->observers很可能还没初始化 accessor 是语言层语法糖,无法访问实例状态(如未声明的私有属性)
- 一旦 notify 报错(比如观察者列表为空或方法不存在),整个赋值会失败,且无明确错误上下文
真正的事件通知,必须由业务方法显式发起,比如 save()、publish() 或 dispatch() —— 这才是可控、可测、可调试的边界。



















