模型中不该直接用 Yii::$app->user->identity->username,因其违反单一职责、导致不可测且在游客或CLI环境下报错;应由控制器传参或用行为自动填充,并始终校验登录状态。

在 Yii2.0.52 的模型(Model)中直接获取登录用户名,**不推荐也不安全**——模型层本应保持无状态、与用户会话解耦。但若业务确需当前登录用户名(例如记录创建人、审核人),应通过**显式传参**或**依赖注入上下文**的方式实现,而非在模型内部硬调 Yii::$app->user。
为什么模型里不该直接用 Yii::$app->user->identity->username
模型(如 ActiveRecord 子类)代表数据实体,职责是数据验证、关系定义和持久化逻辑。它不应感知当前请求上下文:
• Yii::$app 是应用级单例,在 CLI 或队列任务中可能未初始化 user 组件;
• Yii::$app->user->identity 在游客状态(isGuest === true)时为 null,直接访问会触发 PHP Notice 或 Fatal Error;
• 违反单一职责原则,导致模型难以单元测试、复用性差。
推荐做法:由控制器或服务层传入用户名
把用户名作为参数明确传递给模型方法,清晰、可控、可测:
- 在控制器中判断登录状态并提取用户名:
<?php
if (!Yii::$app->user->isGuest) {
$username = Yii::$app->user->identity->username;
$model->setCreatedBy($username); // 假设模型有此方法
}
$model->save();
?>
- 模型中仅接收并保存,不做任何会话判断:
public function setCreatedBy($username)
{
$this->created_by = $username;
return $this;
}
替代方案:使用行为(Behavior)自动填充
若多个模型都需要记录操作人,可封装为行为,在 beforeInsert / beforeUpdate 时自动写入:
- 定义一个
CreatedByBehavior,在events()中监听ActiveRecord::EVENT_BEFORE_INSERT; - 在回调中检查
Yii::$app->user->identity是否存在,存在则赋值到指定属性(如created_by); - 在模型中挂载该行为,无需每次手动传参。
注意:行为内仍需做 !Yii::$app->user->isGuest 判断,避免空引用。
特殊情况:日志或审计场景需强制记录
若模型必须在保存前记录当前操作者(如审批流中的“审核人”字段),且无法修改调用方逻辑,可在模型的 beforeSave() 中谨慎处理:
- 先检查
Yii::$app->has('user')和!Yii::$app->user->isGuest; - 再读取
Yii::$app->user->identity->username; - 对异常情况(如游客、user 组件缺失)提供默认值或抛出有意义的异常,而不是静默失败。
这种方式属于妥协方案,仅限强约束场景,务必加注释说明原因。


















