可在 yii 模型中通过重写 beforesave() 方法自动赋值 created_at 和 updated_at 时间戳:新增时两者均设为当前时间,更新时仅更新 updated_at;也可结合数据库默认值或 rules() 中的 default 验证器(仅推荐用于 created_at),但批量操作需手动在 sql 中处理时间字段。

在 Yii 框架中,不使用行为(Behavior)也能为模型自动赋值创建时间(created_at)和更新时间(updated_at),核心思路是重写模型的生命周期方法,如 beforeSave(),并在其中手动处理时间字段。
在 beforeSave() 中统一处理时间戳
这是最常用、最直接的方式。只需在模型类中覆盖 beforeSave() 方法,判断新增或更新动作,然后给对应字段赋当前时间戳(注意格式需匹配数据库字段类型):
- 若
$this->isNewRecord为true,说明是新记录插入,设置created_at和updated_at - 否则仅更新
updated_at - 时间值推荐用
date('Y-m-d H:i:s')(对应 MySQLDATETIME)或time()(对应INT时间戳)
示例(MySQL DATETIME 类型):
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if ($insert) {
$this->created_at = date('Y-m-d H:i:s');
$this->updated_at = date('Y-m-d H:i:s');
} else {
$this->updated_at = date('Y-m-d H:i:s');
}
return true;
}
return false;
}
配合数据库默认值减少 PHP 层逻辑
如果数据库支持(如 MySQL 5.6+),可将 created_at 设为 DEFAULT CURRENT_TIMESTAMP,updated_at 设为 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。此时 PHP 层只需在 beforeSave() 中确保不覆盖 created_at(尤其新增时未显式赋值),而 updated_at 仍建议在 PHP 中显式更新,以避免依赖数据库触发时机或 ORM 批量操作失效问题。
- 优点:减少代码量,数据库兜底可靠
- 注意:Yii 不会自动感知数据库默认值,新增时不设
created_at可能导致其为NULL(除非字段允许且有默认值) - 稳妥做法:PHP 层仍主动赋值,数据库默认值作为备用保障
使用 rules() 配合 default 值(适用于简单场景)
对于只读默认值(如创建时间仅首次有效),可在模型 rules() 中使用 default 验证器:
public function rules()
{
return [
[['created_at'], 'default', 'value' => date('Y-m-d H:i:s'), 'on' => 'insert'],
[['updated_at'], 'default', 'value' => date('Y-m-d H:i:s')],
// 注意:default 在 load() 后、validate() 前触发,对 isNewRecord 无感知,慎用于 updated_at
];
}
⚠️ 注意:default 规则对 updated_at 不够安全,因为它每次保存都会重置(包括更新操作),无法区分 insert/update。因此更推荐仅用在 created_at,且需配合场景约束(如限定 'on' => 'insert')。
批量操作时的注意事项
使用 ActiveRecord::updateAll() 或原生 SQL 批量更新时,beforeSave() 不会被调用,时间字段不会自动更新。此时必须显式在 SQL 中设置:
User::updateAll(['updated_at' => new \yii\db\Expression('NOW()')], ['id' => $ids]);
- 不能依赖模型层逻辑,必须在 DAO 层补全时间字段
- 若业务中大量使用批量更新,建议封装一个带时间更新的批量方法,避免遗漏











