模型不应调用request,因其职责是封装数据逻辑,而request属于http层;正确做法是由控制器传入必要参数,如validate($data, true, ['user_id' => $uid])。

模型里调用Request会破坏分层职责
不合适。模型(Model)的职责是封装数据逻辑:字段映射、验证规则、关联定义、自动完成、软删除等。而Request属于请求上下文,携带的是 HTTP 层信息(如$request->param('token')、$request->ip()),跟数据库表结构或业务规则毫无关系。
一旦在模型里写use think\Request或Request::instance(),就等于把控制器/中间件层的输入硬塞进数据层,导致:
- 模型无法脱离 HTTP 环境单元测试(比如命令行迁移脚本中调用
UserModel::create()会报错) - 缓存失效风险——模型实例可能被复用,但
Request是单例且每次请求唯一,混用易读到上一次请求的数据 - 依赖倒置:模型不该知道“谁在调用它”,更不该主动去取请求参数;该由上层(控制器)把需要的值作为参数传入
validate()里用Request参数是常见误用点
很多人想在模型的validate规则里动态读取当前请求的user_id做权限校验,于是这么写:
protected $validate = [
['status', 'in:0,1', '状态非法', 'check', function() {
return $this->status == 1 || Request::instance()->param('user_id') == $this->user_id;
}]
];
这会导致三个问题:
-
Request::instance()在 CLI 或队列任务中不存在,直接抛BindingResolutionException - 验证规则闭包里的
$this指向模型实例,但Request不是模型属性,耦合不可控 - 验证逻辑无法复用——比如 API 和后台管理共用同一个模型,但校验条件不同,硬编码在模型里就得加判断分支
正确做法是:把校验所需上下文(如user_id)从控制器传进来,用validate($data, true, ['user_id' => $uid])方式透传,模型内通过$this->data['user_id']或额外参数接收。
替代方案:用think\facade\Request也不解决问题
有人觉得改用静态门面think\facade\Request就能绕过依赖注入问题,其实没用。因为:
-
think\facade\Request底层仍是调用Request::instance(),本质还是全局单例访问 - Facade 只是语法糖,不改变“模型不该感知请求”的设计原则
- 测试时仍需 mock 全局状态,比传参麻烦得多
真正解耦的方式只有一种:让控制器决定“什么数据该进模型”,模型只负责“这些数据合不合法、怎么存”。比如密码重置场景,控制器解析$request->param('token')后,调用UserModel::resetPasswordByToken($token, $newPwd),模型内部只处理$token校验和密码更新,不碰Request。
极少数例外:模型构造时传入Request对象
如果你非要让模型“知道”当前请求,唯一勉强可接受的做法是——把它当作构造参数显式传入,而不是在模型内部主动获取:
class UserModel extends Model
{
protected $request;
public function __construct($data = [], Request $request = null)
{
parent::__construct($data);
$this->request = $request;
}
public function doSomething()
{
if ($this->request && $this->request->isAjax()) {
// 仅当明确传了才用,否则跳过
}
}
}
但注意:
- 必须设默认值
null,否则 CLI 调用直接失败 - 所有使用处都得手动传,不能依赖容器自动注入(容器不会给模型注入
Request) - 这种写法已偏离模型本意,建议优先考虑提取为独立服务类(如
UserActionService)
真正容易被忽略的点是:模型不是“万能胶”,它的边界感比多数人想的更硬。一旦开始在save()、get()、scope里读Request,后面维护的人八成会在某个深夜对着Class 'think\Request' not found抓头发。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











