laravel 6 依赖注入严格依赖反射解析+显式绑定+自动加载,非智能猜测;容器读取构造函数签名,递归解析具体类或已绑定接口,否则报错。

Laravel 6 的服务容器通过反射机制 + 显式绑定 + 自动解析规则,实现类的自动依赖注入。它不是“智能猜测”,而是严格按三步执行:读取构造函数签名 → 检查每个参数类型 → 递归创建并注入实例。
依赖注入靠反射读取构造函数
当容器需要构建一个类(如 OrderController)时,会用 PHP 的 ReflectionClass 分析其 __construct() 方法:
- 若参数是具体类(如
UserRepository),且该类能被自动加载(命名空间正确、文件在app/下、已运行composer dump-autoload),容器就递归解析它 - 若参数是接口(如
PaymentServiceInterface),必须已在AppServiceProvider::register()中用bind()或singleton()绑定实现类,否则抛出Unresolvable dependency - 带默认值的参数(如
CacheService $cache = null)会被跳过,但 PHP 仍要求传参;要真正可选,需写成?CacheService $cache = null
接口必须显式绑定才能注入
接口本身不能被实例化,容器无法凭空知道该用哪个实现。绑定必须在服务提供者的 register() 方法中完成:
-
简单绑定:
$this->app->bind(PaymentServiceInterface::class, StripePaymentService::class);—— 每次请求都新建实例 -
单例绑定:
$this->app->singleton(CacheManager::class, RedisCache::class);—— 整个请求生命周期只创建一次 -
闭包绑定:
$this->app->bind(Mailer::class, function ($app) { return new Mailer(config('mail.host')); });—— 支持运行时取配置或其它服务
注入只在容器调度路径中生效
自动注入不是无条件触发的。只有以下情况才会走容器解析流程:
- 控制器由路由调用(即通过
Route::get(...)访问) - 队列任务被
dispatch()推送后执行 - 事件监听器由
event()触发 - 中间件、命令、任务调度器等 Laravel 内置调度点
如果手动 new UserController(),注入完全不会发生 —— 容器根本没参与对象创建。
常见失败原因很具体
报错往往不是语法问题,而是链路中某个环节断了:
- 绑定写在
boot()而非register()→ 容器已开始解析,绑定被忽略 - 接口类名用了字符串别名(如
'payment')而非完整类常量(PaymentServiceInterface::class)→ 类型提示不匹配 -
use语句漏写或命名空间错误 → 反射读到的是undefined class,最终报Target class [xxx] does not exist - 实现类构造函数有未绑定的接口参数 → 递归解析中断,抛
Unresolvable dependency











