laravel 依赖注入依靠服务容器、php 反射和显式绑定协同工作,缺一不可;构造函数参数通过 reflectionclass 解析类型提示自动填充,接口需提前绑定实现,生命周期错配或绑定时机错误将导致运行时异常。

它靠服务容器 + PHP 反射 + 显式绑定三者协同工作,不是“自动猜”,漏一个环节就报 Target class [xxx] does not exist 或 Unresolvable dependency。
构造函数参数怎么被自动填上?
容器用 ReflectionClass 读取类的 __construct() 签名,逐个检查每个参数的类型提示:
- 如果是具体类(如
CacheService),且该类能被自动加载(命名空间正确、文件在app/下、已运行composer dump-autoload),就递归解析它 - 如果是接口(如
LoggerInterface),必须已在register()中用bind()或singleton()绑定实现类,否则直接抛Unresolvable dependency - 带默认值的参数(如
CacheService $cache = null)会被跳过——但 PHP 仍要求传参,除非写成?CacheService $cache = null
为什么 bind() 和 singleton() 不能乱用?
生命周期错配会引发连接耗尽、状态错乱或缓存失效:
-
bind()每次调用app()->make()都新建实例 → 适合无状态轻量类(DTO、策略类) -
singleton()全局只创建一次 → 必须用于有状态或高开销对象(DB 连接、Redis 客户端、HTTP 客户端) - 误用
bind()绑定PDO实例 → 每次请求新建数据库连接,很快打满连接池 - 用
instance()注入未初始化的对象(比如new SmsService()但env()还没加载完)→ 后续调用抛Undefined index: twilio_sid
Controller 构造函数注入为啥有时不生效?
不是容器坏了,而是时机或路径错了:
- 绑定写在
boot()而非register()→ 容器已开始解析依赖,绑定被跳过(尤其在队列、命令、测试中必现) - 接口绑定用了字符串别名(如
'sms')而非完整类名(如App\Contracts\SmsServiceContract::class)→ 类型提示无法匹配 -
make()只认类名或服务名;resolve()才支持传参数数组覆盖自动注入 —— 生产代码里滥用resolve()会让依赖关系不可追踪 - 路由没走容器调度(比如手动 new Controller)→ 注入根本不会触发
最常被忽略的是绑定时机和接口命名一致性:写错一个 use、少一个 namespace、把 bind() 放错方法,都会让整个链路静默失败。它不报语法错误,只在运行时甩出一句模糊的 “class does not exist”。











