eloquent 没有内置 attribute versioning 功能,也不自动存字段变更快照;所谓“属性版本控制”依赖第三方包(如 laravel-auditing)或自定义实现,isdirty() + getoriginal() 仅支持保存前轻量捕获变更,不持久化。

什么是Eloquent Attribute Versioning,它真能自动存字段变更快照?
不能。Laravel 官方 Eloquent 没有叫 Attribute Versioning 的内置功能,也**不提供自动字段变更快照**。你看到的“属性版本控制”或“字段快照”,基本是第三方包(如 spatie/laravel-activitylog、owen-it/laravel-auditing)或自定义实现的结果。Eloquent 本身只负责模型与数据库映射,getAttributeValue()、isDirty() 这类方法只是辅助判断,不记录历史。
怎么用 isDirty() + getOriginal() 捕获字段变更?
这是最轻量、无依赖的现场抓取方式,适合简单审计或触发逻辑,但不持久化。关键点在于:必须在模型保存前读取,且仅对已加载字段有效。
-
isDirty('email')返回true表示该字段值被修改过(对比原始值) -
getOriginal('email')返回数据库里原来的值,getAttribute('email')返回当前新值 - 注意:如果字段没被
select加载(比如用了select('name')),getOriginal('email')会返回null,不是数据库真实值 - 在
saving或updating事件中使用最安全,避免在saved后调用——此时isDirty()已清空
// 在模型中监听
protected static function boot()
{
parent::boot();
static::updating(function ($model) {
if ($model->isDirty('status')) {
$old = $model->getOriginal('status');
$new = $model->status;
// 记录到日志、发通知、写入 audit 表……
}
});
}
用 owen-it/laravel-auditing 实现字段级快照的实操要点
这是目前最贴近“属性版本控制”需求的成熟方案,但默认行为容易误解:它记录的是整行变更,不是每个字段独立版本号;快照是序列化的 JSON,不是时间线式版本表。
- 安装后需为模型启用审计:
use OwenIt\Auditing\Contracts\Auditable;+implements Auditable+AuditableTrait - 关键配置在
$auditInclude:只列你想跟踪的字段,否则默认审计所有可填充字段(含敏感字段风险) - 审计记录存在
audits表,new_values和old_values是 JSON 字段,包含本次变更的键值对,不是全量快照 - 不支持“回滚到某次属性值”——它不存中间状态,只存 diff。要还原某个字段的历史值,得遍历 audits 表反向推演
- 性能敏感场景慎用:每次 save 都多一次 insert,高并发时可能成瓶颈;建议配合队列异步审计(
AuditCustomSettings中设queue=> true)
为什么别自己手写“版本表”来存每个字段的变更?
看似灵活,实际很快失控。典型问题包括:
- 字段增减需同步改版本表结构,迁移脚本爆炸式增长
- 查询“用户手机号第 3 次修改时间”需要多层 JOIN 或 JSON 解析,索引失效
- 软删除模型的版本记录是否也软删?一致性难保障
- Eloquent 关系(如
user()->posts)无法自然关联到某次 post.title 的版本,上下文丢失
真正需要字段级时间线追溯的场景(比如合规审计),应优先考虑专用系统(如 Temporal DB)或物化视图,而不是在 Laravel 应用层硬扛版本逻辑。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











