Request 对象在 $app->http->run() 阶段首次创建,由 think\Http 按需调用 Request::createFromGlobals() 构造;创建后立即以 think\Request 为键单例绑定至容器,供后续依赖注入、Facade 或 app() 获取。

Request 对象什么时候被创建
ThinkPHP 的 Request 对象不是在应用启动时就立即实例化的,而是在 HTTP 驱动真正开始处理请求、进入 $app->http->run() 阶段才首次生成。TP8 中它由 think\Http 类内部按需调用 Request::createFromGlobals() 或根据 CLI/HTTP 上下文构造,确保对象携带的是当前真实请求数据。
Request 对象如何绑定到容器
创建后,Request 实例会立刻被绑定进容器,键名为 think\Request(TP8)或 request(部分 TP6 模板)。这意味着后续任何通过依赖注入或 app()->make('think\Request') 获取的都是同一个实例——它是单例,但仅限本次请求生命周期内有效。
- 控制器方法参数注入:直接写
public function index(Request $request),框架自动解析并传入已初始化的实例 - Facade 调用:
think\facade\Request::param()底层也是从容器取这个已绑定的对象 - 手动获取:
app('think\Request')或app()->get('think\Request')效果相同,但不推荐绕过 DI
为什么不能在中间件之前访问 Request 的某些属性
虽然 Request 对象在 http->run() 开头就创建了,但它内部的 pathinfo、method、input 等关键属性,依赖于全局中间件(如 SessionInit、CheckLang)执行后的上下文补全。例如:
-
Request::url()可能含 host 重写结果,这由跨域或反向代理中间件修正 -
Request::param()默认合并 GET+POST+ROUTE 参数,而路由参数要等Route中间件执行后才解析出来 - 若在全局中间件管道外(比如自定义服务提供者里)提前调用
Request::ip(),可能返回空或不准确值
继承 app\Request 时要注意初始化时机
如果你在 app\Request 中覆写了 __construct 或添加了初始化逻辑(比如自动解密 header),必须确认该类仍遵循框架的创建流程——它不能在容器绑定前就被 new 出来。正确做法是:
立即学习“PHP免费学习笔记(深入)”;
- 保持
app\Request继承think\Request,不重写构造函数主体 - 把需要“预处理”的逻辑移到
initialize()方法中(TP8 支持),该方法会在容器完成实例化、属性注入后自动调用 - 避免在静态方法或配置加载阶段引用
Request,此时容器甚至还没完成初始化
最易被忽略的一点:Request 对象的“初始化完成”不等于“可用属性全部就绪”,它的语义完整性依赖中间件链的推进顺序,而不是构造动作本身。



















