thinkphp时间戳自动写入需模型配置、字段名、类型三者对齐,否则save/update失效;常见失效原因包括未配$createtime/$updatetime、未声明$type、绕过模型层、数组传参跳过赋值流程、状态变更需手动控制、与$readonly或数据库默认值冲突。

ThinkPHP 的数据库字段自动维护不是开箱即用的功能,必须在模型中显式声明配置项、字段名、类型三者对齐,否则 save() 或 update() 时字段根本不会被自动写入。
为什么 $autoWriteTimestamp = true 没生效
常见失效场景有三个,缺一不可:
- 模型里没配
$createTime和$updateTime字段名(比如数据库是created_at,但模型仍用默认create_time) - 字段类型是
DATETIME,但没在$type中声明:protected $type = ['created_at' => 'datetime'] - 用了
Db::name('user')->update()这类原生查询——它完全绕过模型层,时间戳逻辑压根不触发
save() 传数组 vs 实例赋值,时间字段行为完全不同
这是最容易踩坑的点:直接传数组会跳过模型属性赋值流程,导致时间戳感知失效。
-
User::save(['id' => 1, 'name' => 'xxx'])→updateTime不更新 -
$user = User::find(1); $user->name = 'xxx'; $user->save();→updateTime正常更新 - 若必须用数组更新,得强制启用:
User::update(['id' => 1, 'name' => 'xxx'], [], ['force' => true])
状态变更类时间字段(如 disable_time)不能靠自动时间戳
ThinkPHP 的 $createTime/$updateTime 只响应「新增/更新」动作,不感知业务状态变化。停用、激活、冻结等时间点必须手动控制。
- 推荐在模型
beforeWrite钩子中比对$this->origin和$this->data - 例如:
if ($this->data['status'] == 0 && $this->origin['status'] == 1) { $this->data['disable_time'] = date('Y-m-d H:i:s'); } - 注意:
$this->origin在新增时为空,需单独判断,否则会报 Notice
字段冗余和自动填充混用时的冲突风险
当同时用 $insert/$update 属性 + 时间戳 + 修改器时,顺序和优先级容易出错。
-
setUpdateTimeAttr()会在$update自动填充之后执行,若两者都写update_time,可能被覆盖 -
$readonly = ['update_time']会彻底禁用该字段写入,连自动时间戳也拦住 - 如果数据库字段设了
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,和 PHP 层自动写入会竞争,建议只留一端控制
真正麻烦的从来不是“怎么写”,而是“哪一层在管”——模型配置、数据库约束、控制器手动赋值、修改器、钩子,五处都可能插手同一个字段。一旦没对齐,时间就乱、状态就丢、缓存就 stale。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











