ThinkPHP中模型字段如何实现自动填充创建和更新时间戳?

2026-04-30 11:282阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计881个文字,预计阅读时间需要4分钟。

ThinkPHP中模型字段如何实现自动填充创建和更新时间戳?

ThinkPHP+6+的模型时间戳是opt-in机制,默认不启用。需要显式开启时间戳功能,并且确保字段名、类型、配置三者对应正确。

  • 必须在模型类中设置 protected $autoWriteTimestamp = true;(或具体指定 'datetime' / 'int'
  • 字段名默认是 create_timeupdate_time,若数据库用的是 createTime,需同步改 protected $createTime = 'createTime';protected $updateTime = 'updateTime';
  • createTime 只在 save() 且主键为空(即新增)时触发;updateTimesave() 且主键存在时更新——但手动调用 update() 静态方法时,默认不走模型时间戳逻辑,得加 ['force' => true]

为什么 save(['id' => 1, 'name' => 'xxx']) 没更新 updateTime

因为 ThinkPHP 默认只对「模型实例的属性变更」做时间戳感知,直接传数组给 save() 会跳过属性赋值流程,导致 updateTime 不被识别为待更新字段。

  • 正确做法:先查出模型实例,再改属性,再 save()

    $user = User::find(1);<br>$user->name = 'xxx';<br>$user->save();

  • 或强制启用时间戳:用 User::update(['id' => 1, 'name' => 'xxx'], [], ['force' => true]),但注意这会绕过模型事件和验证
  • 如果用 Db::name('user')->update(...),时间戳完全不生效——这是原生查询,模型层逻辑根本不参与

createTime 被重复覆盖,比如编辑时也重写了创建时间?

常见于字段名冲突或配置松动:当 $createTime$updateTime 指向同一字段,或未关闭自动写入逻辑,就容易误刷。

  • 确认两者指向不同字段:protected $createTime = 'create_time'; protected $updateTime = 'update_time';
  • 若不需要自动写入 createTime(比如从 Excel 导入已有时间),可设 protected $autoWriteTimestamp = ['update_time' => 'datetime'];,只管更新时间
  • 数据库字段类型要匹配:用 datetime 就配 'datetime',用 int 时间戳就配 'int',否则可能写入 0 或报错 DateTime::__construct(): Failed to parse time string

MySQL 5.6+ 的 DEFAULT CURRENT_TIMESTAMP 和 ThinkPHP 时间戳能共存吗?

能,但容易互相干扰——尤其在批量插入或忽略字段时,数据库默认值和 PHP 层填充会竞争。

立即学习“PHP免费学习笔记(深入)”;

  • 推荐只留一端控制:要么全交给 ThinkPHP(关掉数据库默认值,字段设为 NULL),要么全交给数据库(模型里关掉 $autoWriteTimestamp,靠 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  • 若两边都开,createTime 可能被 PHP 写一次、数据库又写一次;更糟的是,某些 MySQL 配置下 ON UPDATE 会对 INSERT 也触发,导致创建时间被刷成当前时间
  • 调试时看 SQL 日志最准:think.log 里搜 INSERT INTO user,确认字段是否含 create_time
字段名、配置项、SQL 层默认值这三处必须咬死一致,少一个对不上,时间就填错位置或者干脆不填。
标签:PHPThinkPHP

本文共计881个文字,预计阅读时间需要4分钟。

ThinkPHP中模型字段如何实现自动填充创建和更新时间戳?

ThinkPHP+6+的模型时间戳是opt-in机制,默认不启用。需要显式开启时间戳功能,并且确保字段名、类型、配置三者对应正确。

  • 必须在模型类中设置 protected $autoWriteTimestamp = true;(或具体指定 'datetime' / 'int'
  • 字段名默认是 create_timeupdate_time,若数据库用的是 createTime,需同步改 protected $createTime = 'createTime';protected $updateTime = 'updateTime';
  • createTime 只在 save() 且主键为空(即新增)时触发;updateTimesave() 且主键存在时更新——但手动调用 update() 静态方法时,默认不走模型时间戳逻辑,得加 ['force' => true]

为什么 save(['id' => 1, 'name' => 'xxx']) 没更新 updateTime

因为 ThinkPHP 默认只对「模型实例的属性变更」做时间戳感知,直接传数组给 save() 会跳过属性赋值流程,导致 updateTime 不被识别为待更新字段。

  • 正确做法:先查出模型实例,再改属性,再 save()

    $user = User::find(1);<br>$user->name = 'xxx';<br>$user->save();

  • 或强制启用时间戳:用 User::update(['id' => 1, 'name' => 'xxx'], [], ['force' => true]),但注意这会绕过模型事件和验证
  • 如果用 Db::name('user')->update(...),时间戳完全不生效——这是原生查询,模型层逻辑根本不参与

createTime 被重复覆盖,比如编辑时也重写了创建时间?

常见于字段名冲突或配置松动:当 $createTime$updateTime 指向同一字段,或未关闭自动写入逻辑,就容易误刷。

  • 确认两者指向不同字段:protected $createTime = 'create_time'; protected $updateTime = 'update_time';
  • 若不需要自动写入 createTime(比如从 Excel 导入已有时间),可设 protected $autoWriteTimestamp = ['update_time' => 'datetime'];,只管更新时间
  • 数据库字段类型要匹配:用 datetime 就配 'datetime',用 int 时间戳就配 'int',否则可能写入 0 或报错 DateTime::__construct(): Failed to parse time string

MySQL 5.6+ 的 DEFAULT CURRENT_TIMESTAMP 和 ThinkPHP 时间戳能共存吗?

能,但容易互相干扰——尤其在批量插入或忽略字段时,数据库默认值和 PHP 层填充会竞争。

立即学习“PHP免费学习笔记(深入)”;

  • 推荐只留一端控制:要么全交给 ThinkPHP(关掉数据库默认值,字段设为 NULL),要么全交给数据库(模型里关掉 $autoWriteTimestamp,靠 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  • 若两边都开,createTime 可能被 PHP 写一次、数据库又写一次;更糟的是,某些 MySQL 配置下 ON UPDATE 会对 INSERT 也触发,导致创建时间被刷成当前时间
  • 调试时看 SQL 日志最准:think.log 里搜 INSERT INTO user,确认字段是否含 create_time
字段名、配置项、SQL 层默认值这三处必须咬死一致,少一个对不上,时间就填错位置或者干脆不填。
标签:PHPThinkPHP