ThinkPHP 6/8 中控制器方法参数声明 Request 类型可自动注入框架原生请求实例,需 use think\Request;继承 Controller 后通过 $this->request 访问同一实例;中间件中必须用 $request->with() 添加上下文数据。

控制器方法参数直接写 Request 就能自动注入
ThinkPHP 6/8 默认支持在控制器方法签名里声明 Request 类型参数,框架会在调用前自动从容器取单例实例传入——不需要手动 new,也不依赖 Request::instance()。
常见错误是写了类型但没加 use think\Request,导致 PHP 报 Class 'app\index\controller\Request' not found;或者用了别名(如 use app\Request)却没继承或重写,结果注入的是自定义类而非框架原生对象。
- 必须
use think\Request,不是app\Request(除非你明确重写了它) - 方法参数名可以任意(
$request、$req都行),关键看类型声明 - 该方式只对容器接管的调用生效(即路由匹配到的控制器方法),普通函数调用不触发
- TP8 中
Request是 singleton,所有注入点共享同一实例,修改$request->with()会影响后续同请求中的其他方法
继承 Controller 后用 $this->request
这是最省事的写法,适合多数 CRUD 场景。系统基类 think\Controller 在构造时已把 Request 实例绑定到 $this->request 属性,无需额外声明或导入。
容易踩的坑是:自己写了构造函数却忘了调用 parent::__construct(),导致 $this->request 为 null;或者在 TP8 中误以为继承后还能覆盖 $this->request,实际上它被设为只读属性,硬赋值会静默失败。
- 必须
use think\Controller并extends Controller - 如果重写了
__construct(),第一行得是parent::__construct(...) -
$this->request和方法参数注入的Request是同一个对象(同一内存地址) - TP8.1+ 中
$this->request不再允许直接赋值,$this->request = new Request()会报错
用助手函数 request() 或静态 Request::instance()
这两种是“兜底方案”,适合临时调试、非标准调用链(如事件监听器、命令行指令),但不推荐在常规控制器逻辑中混用,容易造成请求对象生命周期混乱。
request() 是全局函数,本质就是从容器取 Request::class 实例;Request::instance() 是兼容旧版的静态代理,TP8 中已标记为废弃(仍可用,但文档不提)。两者都绕过了容器的依赖解析流程,无法参与自动注入链(比如中间件里 with() 注入的数据,在 Request::instance() 调用前未初始化就拿不到)。
-
request()更轻量,且与容器强绑定,TP8 中推荐优先用它 -
Request::instance()在 TP5.1 中是唯一方式,TP6+ 起逐步过渡到容器驱动 - 在中间件里获取当前请求对象,必须用
$request参数本身,不能在中间件里调request()——此时容器可能还未完成初始化 - 多个地方混用
request()和参数注入,会导致难以追踪数据流向(比如with()是挂在哪次实例上的)
中间件里给 Request 追加数据,必须用 with() 而非属性赋值
想在中间件里塞用户 ID、权限信息等上下文,不能写 $request->user_id = 123——Request 类有 __set() 拦截,TP6.0+ 直接忽略,TP5.1 可能报 Attempt to assign property。
with() 才是正道:它把键值存进参数池(param() 底层容器),控制器里 $request->param('user_id')、验证器、only() 全都能感知;而 extend() 只是往对象挂属性,param() 里查不到,验证器也校验不到。
-
$request = $request->with('uid', $uid ?? null)必须重新赋值,Request是不可变对象 - 链式调用安全:
$next($request->with('uid', $uid)->with('source', 'api')) - 分支逻辑中务必保证所有路径都调
with(),否则部分请求缺失字段 - TP6.3+ 支持多键数组:
$request->with(['uid' => 123, 'role' => 'admin'])
真正复杂的地方在于:with() 注入的数据只存在于当前请求生命周期,且依赖容器初始化顺序;如果你在入口文件之外另起一个 CLI 命令或异步任务,bindRequest() 根本没执行,with() 就会失效——这时候得回退到 extend() 或显式传递上下文。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











