thinkphp中间件由容器统一创建和管理,通过think\container的make()和invoke()方法实现依赖注入与参数自动传递,其生命周期、单例复用、类型提示校验及容器耦合均受框架容器深度控制。

中间件实例由容器创建和管理
ThinkPHP 的中间件不是手动 new 出来的,而是由 think\Container 负责实例化。当你在路由中写 ->middleware(\App\Middleware\Auth::class),框架不会直接调用 new Auth(),而是调用 $container->make(\App\Middleware\Auth::class)。这意味着:
- 中间件的构造函数参数会自动从容器解析(比如注入
Log、Cache或自定义 Service) - 如果该中间件类在容器中被绑定为单例(
singleton()),多次请求复用同一个实例 - 若构造函数参数类型提示缺失(如 PHP 8 下未写
\think\Request $request),容器反射失败,抛出BindingResolutionException
中间件注册过程依赖容器的服务提供者机制
全局中间件列表(app/middleware.php)本身不参与依赖注入,但它注册的类,会在应用启动时被 think\App::boot() 扫描并交由容器统一调度。关键点在于:
-
app()->bind('middleware.auth', \App\Middleware\Auth::class)这类显式绑定,能让中间件以别名方式被复用(如在不同路由中都用app('middleware.auth')) - 服务提供者(
ServiceProvider)可在register()阶段向容器注入中间件所需依赖,例如预配置一个带 JWT 验证器的Auth实例 - TP8 中,
think\Http类内部使用$this->app->make()创建中间件管道,因此中间件生命周期完全受容器控制
中间件 handle() 方法的参数注入靠容器 invoke() 实现
中间件的 handle() 方法签名必须是 handle(\think\Request $request, \Closure $next),但你实际写的代码里并不需要手动传参——这是容器的 invoke() 在背后工作:
- 框架调用
$container->invoke([$middleware, 'handle'], [$request, $next]) - 容器通过
ReflectionParameter::getType()检查类型提示,自动将当前请求对象和闭包注入 - 如果你把
$request参数类型提示写成Request(漏掉命名空间),PHP 8+ 会因联合类型解析失败导致中间件静默跳过,不报错也不执行 - 闭包参数
$next必须是\Closure,否则容器无法识别其可调用性,直接中断 pipeline
容易被忽略的耦合点:中间件里的 $this->app 就是容器本身
在中间件内部,$this->app 不是独立对象,而是对 think\App 的引用;而 think\App 继承自 think\Container。这意味着:
- 你在中间件里调用
$this->app->make('cache')或$this->app->bind('foo', ...)是合法的,但不推荐——这会让中间件承担容器管理职责 - 若在中间件中修改了容器绑定(如重 bind 日志驱动),会影响后续所有请求,造成状态污染
- TP8 的严格 PSR-11 兼容性意味着:任何第三方 PSR-11 容器(如 Symfony DI)无法直接替换 TP 的容器,因为中间件链深度耦合了
think\Container的invoke()和make()行为
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











