新建模型实例时时间戳字段需通过TimestampBehavior在保存前自动填充,不可用构造函数或手动赋值;须配置behaviors()方法,指定value为数据库NOW()或PHP date(),并确保字段不参与验证和表单提交。

新建模型实例时,时间戳字段不会自动赋值,必须靠行为(Behavior)在保存前触发填充,而不是靠构造函数或手动 set。
用 TimestampBehavior 统一管理
这是最标准、最推荐的方式。在模型类的 behaviors() 方法中配置,让框架在插入/更新前自动写入时间值:
- 确保模型已继承
yii\db\ActiveRecord - 数据库字段如
created_at和updated_at类型建议为DATETIME或TIMESTAMP(MySQL) - 行为中指定
'value' => new \yii\db\Expression('NOW()'),让数据库生成时间,精度高且时区可控 - 若用 PHP 时间,可写
'value' => function() { return date('Y-m-d H:i:s'); },但要注意时区设置(如date_default_timezone_set('Asia/Shanghai'))
字段不参与验证和赋值
因为时间戳由行为自动处理,所以这些字段:
- 不能出现在 rules() 中(否则可能被清空或校验失败)
- 不应在控制器里手动
$model->created_at = ...赋值 - 也不该在表单提交时传入,否则会覆盖行为逻辑
注意事件触发时机
TimestampBehavior 默认只响应两个事件:
-
ActiveRecord::EVENT_BEFORE_INSERT→ 填充createdAtAttribute和updatedAtAttribute -
ActiveRecord::EVENT_BEFORE_UPDATE→ 只填充updatedAtAttribute - 行为生效前提是模型调用
save(),且验证通过;验证失败时行为不执行
特殊情况:想新建实例就看到时间值
如果只是想在 new Model() 后立刻看到时间字段有值(比如用于调试或前端预览),可以临时加一个 getter 或初始化逻辑:
- 不推荐在
init()里直接设时间,因为此时还没进保存流程,容易和行为冲突 - 更安全的做法是定义一个只读属性,如
getCreatedAtPreview(),返回date('Y-m-d H:i:s') - 真正入库仍以 behavior 为准,避免双写导致不一致











