getOriginal() 返回模型首次从数据库加载时的原始值,而非上次保存的值;它在 retrieved 事件时初始化,后续 save() 不会更新,需结合 getDirty() 或手动快照才能准确对比变更。

getOriginal() 返回的是数据库原始值,不是“上次保存的值”
很多人以为 getOriginal() 能拿到模型上一次 save() 之前的属性快照,其实不是。它只在模型从数据库加载(如 find()、first())那一刻被初始化,之后无论你改多少次、调多少次 save(),getOriginal() 始终指向**首次查出来的那组值**。
常见错误现象:
– 模型修改后 save(),再改一次又 save(),用 getOriginal('name') 对比发现和当前值一样
– 在监听 saving 事件里对比 getOriginal() 和 getAttribute(),结果始终没变化
- 真正想对比“变更前后”,得自己存快照:比如在
boot()中监听retrieved事件,手动备份到临时属性 - 或改用
$model->getChanges()—— 它返回本次save()前被修改过的字段及新值,但不提供旧值 -
getOriginal()的值不可写,也不能通过setOriginal()覆盖(Laravel 无此方法)
getAttribute() 不等于 “当前内存值”,它受访问器影响
getAttribute('status') 看似取当前值,但实际会触发对应访问器(getStatusAttribute()),而 getOriginal('status') 绕过访问器,直接读原始数据库字段值。两者类型或格式可能不一致。
使用场景:
– 需要校验“用户是否真改了数据库字段”(比如 status 字段被访问器转成中文,但数据库仍是 0/1)
– 做审计日志时,原始字段值比展示值更可靠
- 若字段有访问器且返回非原始类型(如把
1变成"启用"),getAttribute('status')返回字符串,getOriginal('status')返回整数 - 访问器中抛异常会导致
getAttribute()失败,但getOriginal()不受影响 - 批量赋值(
fill())不会触发访问器,所以getAttribute()和getOriginal()在刚fill()后可能暂时一致
对比变更最稳妥的方式:用 getDirty() + getOriginal() 手动组合
没有现成的“获取某字段变更前/后值”的单函数。必须靠 getDirty() 判断是否改动,再分别取 getOriginal($key) 和 getAttribute($key)。
示例逻辑:
if ($user->isDirty('email')) {
$old = $user->getOriginal('email');
$new = $user->getAttribute('email');
// 记录:从 $old → $new
}
-
isDirty('email')是必要前提,否则getOriginal('email')可能和当前值相同,导致误判 - 注意:如果字段是
null,且数据库允许 null,getOriginal()返回null,但getAttribute()可能被访问器转成空字符串或默认值 - Laravel 9+ 支持
wasChanged('email')(仅限已保存过的模型),但它内部也是基于getOriginal()和当前值比对,不能替代手动判断
事件中拿不到“变更前值”?因为 retrieved 事件只触发一次
在 saving 或 updating 事件里想对比,你会发现 getOriginal() 还是初始值 —— 因为模型没重新查库,getOriginal() 不会自动更新。
容易踩的坑:
– 在控制器里 $user->name = 'new'; $user->save();,然后进 updating 事件,以为 getOriginal('name') 是上一次保存的值
– 实际它还是第一次 find() 时的值,中间哪怕多次 save(),它也不变
- 解决办法只有两个:一是在
retrieved事件里把原始值存到私有属性(如$this->originalSnapshot = $this->getAttributes(););二是用包如owen-it/laravel-auditing - 别依赖
getOriginal()做业务判断,比如“只有 email 改了才发验证邮件”——它可能漏掉第二次修改 - 如果模型是 new 实例(
$user = new User),getOriginal()返回空数组,getOriginal('id')返回null
getOriginal() 当成“上一次 save 的快照”,它不是。


















