getoriginal()是唯一可靠方式,但只对find()等单条加载的实例有效;它返回数据库原始值,不受获取器/修改器影响,save()后origin被覆盖,故新旧对比须在save前完成快照。

getOriginal() 是唯一可靠方式,但只对 find() 加载的实例有效
想拿到数据库里刚查出来的、没被任何获取器或修改干扰的原始值,必须用 getOriginal()。它返回的是模型初始化时从数据库读出的原始字段数组,比如数据库存的是 0,getOriginal()['status'] 就是 0,不是 false;存的是 '2026-04-01',就不会被自动转成 DateTime 对象。
但这个方法有硬性前提:模型必须是通过 find()、findOrFail()、get() 等单条加载方式创建的。用 new User() 或 User::create() 得到的空模型,调用 getOriginal() 只会返回空数组。
- 错误做法:
$user = new User(); $user->getOriginal()→ 返回[] - 正确做法:
$user = User::find(1); $user->getOriginal()→ 返回真实原始字段 - 注意:批量查询(如
all())返回的是对象数组,每个对象仍可单独调用getOriginal()
getData() 和直接访问属性的区别在哪
getData() 返回的是当前模型 data 属性里的全部字段,但它可能已被获取器(accessor)处理过。比如你定义了 getStatusAttr() 把 0/1 转成 '禁用'/'启用',那么 $user->getData('status') 返回的就是中文字符串,不是原始数字。
而直接访问 $user->status 的行为取决于是否定义了获取器——有则触发,无则等价于 getData('status')。所以它也不保证原始性。
- 要原始值:只信
getOriginal()(单条加载后)或getData('field', true)(ThinkPHP 6.3+ 支持第二个参数强制跳过获取器) - 要当前值(含获取器效果):用
$user->status或$user->getData('status') -
getData()不传字段名时返回整个数组,但仍是“当前值”,不是原始值
save() 后 getOriginal() 还能用吗
不能。一旦调用 save(),模型内部会执行 $this->origin = $this->data,把当前数据覆盖到 origin 属性上。此时再调 getOriginal(),拿到的是刚写入后的值,不是数据库里原来的旧值。
这意味着:如果你要做新旧对比,必须在修改字段之后、调用 save() 之前完成快照。常见错误是先 $user->name = '新名字'; $user->save();,再回头想取旧值——已经晚了。
- 安全时机:查出来立刻存一份
$old = $user->getOriginal(); - 对比逻辑建议放在控制器或服务层,别依赖 save 后再取
- 批量更新(
saveAll())不维护原始快照,每个模型的origin在保存后都被重置,无法回溯
为什么 getOriginal() 比 getData('field', true) 更值得依赖
getData('field', true) 是 ThinkPHP 6.3 引入的绕过获取器方式,但它依赖模型当前 data 的内容。如果字段被 setter 修改过(比如 setNameAttr()),data 里存的已经是处理后的值,getData('field', true) 拿到的也不是数据库原始值。
getOriginal() 则完全不经过 setter/getter 流程,它读的是模型构造时固化下来的那一份快照,只要没被 save() 覆盖,就始终可信。
- 场景差异:
getData('field', true)适合「当前数据中跳过获取器」;getOriginal()适合「还原数据库那一刻的状态」 - 兼容性:
getData(..., true)在 TP6.0–6.2 不可用,getOriginal()自 TP6 起稳定支持 - 最易被忽略的一点:字段类型差异。比如数据库字段是 JSON 类型,
getOriginal()返回字符串,getData()可能已自动 json_decode 成数组——这种隐式转换会让对比失效
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











