isDirty() 对比原始加载状态与当前值,非实时检测修改;手动赋值attributes、新模型fill()、syncOriginal()后均致其失效;wasChanged()仅在save后有效,反映上次保存时是否变更。

Eloquent 的 isDirty() 不是实时反映“当前修改”,而是对比「原始加载状态」和「当前属性值」——没调用 save() 之前,它只管你改没改,不管改得对不对、合不合理。
为什么 isDirty() 有时返回 false,明明字段值已经变了?
常见于手动赋值后未触发属性变更跟踪,比如直接操作数组或绕过访问器:
- 用
$model->attributes['name'] = 'new'而非$model->name = 'new',跳过了 Eloquent 的 setter 机制,original不更新,isDirty()失效 - 批量赋值时用了
fill()但模型刚 new 出来(无 original 数据),此时isDirty()永远返回 false - 调用
$model->syncOriginal()后主动重置了原始快照,后续所有变更都“不算脏”
isDirty() 和 wasChanged() 的关键区别在哪?
isDirty() 看的是「现在有没有变」,wasChanged() 看的是「上次 save 时有没有变」——后者只在 save() 或 update() 执行后才有意义:
-
$user->name = 'Alice'; $user->isDirty('name')→true(还没存) -
$user->save(); $user->wasChanged('name')→true(刚存完立刻查) -
$user->name = 'Bob'; $user->wasChanged('name')→ 还是true(不会自动刷新,除非再 save) -
$user->isDirty('email')在未修改 email 时始终为false,哪怕其他字段已变
如何检测某个字段是否「真被用户改过」,排除初始化/默认值干扰?
不能只靠 isDirty(),得结合 getOriginal() 和当前值做语义判断:
// 判断 name 是否被显式修改(而非构造时带的默认值)
$originalName = $user->getOriginal('name');
$currentName = $user->name;
// 注意:null 和 '' 可能语义不同,按业务决定是否视为变更
if ($originalName !== $currentName && !($originalName === null && $currentName === '')) {
// 确实改了,且不是从 null 变成空字符串这类模糊情况
}
- 避免用
==,必须用!==防止类型隐式转换(如'0' == 0) - 如果字段有 accessor/mutator,
$user->name已是处理后值,getOriginal()是原始数据库值,二者比较才真实 - 对 JSON 字段或数组,要用
json_encode()+===比较,否则引用或顺序差异会导致误判
真正难的不是调用 isDirty(),而是理解它背后那个静态的 original 数组什么时候被写入、什么时候被覆盖——一次 refresh()、一次 replicate()、甚至一个 toArray() 都可能间接影响它的行为。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











