ThinkPHP依赖注入由服务容器驱动,通过反射识别类型提示并从容器中获取或构建实例。App类即容器,统一管控绑定、单例、延迟加载等;Request为典型单例注入,入口初始化后全局复用;构造函数与方法参数注入共用同一机制,支持接口绑定与闭包绑定。

ThinkPHP 的依赖注入不是“自动猜类型”或“读全局变量”,而是由服务容器驱动的一整套可控、可追溯、可扩展的实例化与装配机制。核心在于:容器提前注册并管理对象生命周期,调用时通过反射精准识别类型提示,再从容器中取出(或构建)对应实例完成注入。
服务容器是整个应用的根基
ThinkPHP 8 中 App 类直接继承自容器基类,意味着“应用即容器”。所有服务注册、依赖解析、对象创建、方法调用都走同一套容器逻辑。它不只是个工厂,更是服务治理中枢——统一管控绑定、单例、延迟加载、作用域和解析策略。
常见操作本质都是容器行为:
-
app(UserService::class)→ 调用容器make()方法,触发依赖递归解析 -
bind('cache', RedisCache::class)→ 在容器中建立标识到类的映射关系 -
app()->invoke([$controller, 'index'])→ 不直接执行方法,而是交由容器处理参数注入
依赖注入靠反射 + 容器协同完成
当你在控制器方法里写 public function index(Request $request),框架不会去猜测或手动 new,而是:
- 路由匹配后,不调用
$controller->index(),改用容器的invoke() - 通过
ReflectionMethod扫描该方法所有参数 - 对每个参数,用
ReflectionParameter::getType()->getName()获取完整类名(如think\Request) - 调用
container->make(‘think\Request’)—— 因为启动时已用singleton()注册,直接返回缓存实例 - 最终用
invokeArgs()把实例作为实参传入执行
这套流程适用于控制器方法、路由闭包、中间件、事件监听器、命令行指令等所有容器接管的可调用对象。
Request 对象是典型单例注入案例
请求对象的注入最能体现容器初始化与复用的设计意图:
- 入口文件
public/index.php加载应用后,立即执行bindRequest() - 该方法将
think\Request绑定为单例,并触发一次make(),完成完整初始化(解析$_SERVER、合并输入数据、挂载钩子等) - 实例被存入容器的
$instances数组,后续任何地方类型提示Request,都返回同一个实例 - 若入口不唯一(比如多入口或 CLI 直接 require 控制器),
bindRequest()不执行,Request实例根本不存在,注入失败抛出BindingResolutionException
构造函数注入与方法注入共用同一套机制
无论是控制器构造函数还是操作方法参数,只要带类型提示,就走反射+容器 make 流程:
- 构造函数注入:
public function __construct(Cache $cache, Config $config)→ 创建控制器实例时自动解析 - 方法注入:
public function detail($id, UserService $service)→ 执行该方法前注入,适合临时性、场景化依赖 - 两者都支持接口绑定,例如
app()->bind(CacheInterface::class, RedisCache::class),业务层只依赖接口,实现可随时切换
容器还支持闭包绑定、配置数组绑定、抽象类映射等高级方式,为测试 Mock、环境隔离、驱动替换提供底层支撑。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











