模型事件不触发主因是配置或调用时机问题:需确保app.event=true、事件在protected static init()中注册、且仅在模型方法(如save)中触发,绕过模型的Db操作无效。

模型事件不触发,90% 是配置或调用时机问题,不是代码写错了。
app.event 是否开启?CLI 环境特别容易失效
ThinkPHP 模型事件依赖全局事件系统,app.event 关闭会导致 beforeInsert、afterWrite 等全部静默失效。
- 确认
config/app.php中'event' => true(TP6.1+ 默认开启,但 CLI 环境可能加载独立配置) - TP6.3+ 已移除
model.event配置项,若还在config/model.php里设'event' => true,它已完全无效 - CLI 命令下常因缓存未更新或加载了
app_cli.php导致app.event = false,必须运行php think config:clear后重启命令
事件是否在 init() 中注册?别在构造函数或控制器里临时挂载
模型事件不会自动扫描方法名,也不会按命名约定绑定。写了 onBeforeInsert 但没注册,它就是普通静态方法,根本不会执行。
- 必须在模型类中定义
protected static function init() - 在
init()中调用self::event('before_insert', [...])或快捷方式self::beforeInsert(...) - 子类继承时,
init()不会自动调用parent::init(),必须显式补上 - 避免在控制器、
__construct()或 service 中调用self::event()—— 这些位置不可靠,可能漏注册或重复绑定
是不是绕过了模型?Db::insert() 和批量操作都不触发事件
模型事件只在 Model::save()、Model::delete()、Model::find() 等模型方法中触发。任何绕过模型实例的操作,事件都不会激活。
-
Db::name('user')->insert([...])或Db::table('user')->update(...):不走模型,事件完全不触发 -
UserModel::where()->update(...)或UserModel::saveAll([...]):不创建单个模型对象,只执行原生 SQL,生命周期钩子跳过 -
$model->create($data)在 TP6.0 已废弃,调用直接报错Method create does not exist - 想自动填充字段,改用
before_insert/before_update事件,或setPasswordAttr这类访问器
afterWrite 和 afterUpdate 的触发时机差异很关键
这两个事件不是并列关系,触发条件和数据状态完全不同,混用极易踩坑。
-
afterUpdate只在模型已存在主键、明确走更新流程时触发,此时$model->id必然有值,适合刷新关联缓存、通知下游系统 -
afterWrite在新增和更新后都会触发,但事务尚未提交,外部服务查不到新数据;若发 HTTP 请求或写 MQ,要考虑事务回滚导致的数据不一致 - 需要判断动作类型时,优先用
beforeInsert/beforeUpdate,而不是在beforeWrite里手动if ($model->isUpdate())分支——此时主键检测可能还没完成 - 在
after_delete里调用$this->find()查不到数据是正常设计,不是 bug
真正复杂的地方在于:事件注册、配置开关、调用路径三者必须同时对齐。少一个环节,就静默失效,连错误提示都没有。


















