laravel 6 的 when()->needs()->give() 用于上下文限定绑定,即在特定类解析时为其构造函数参数注入指定值或实例;适用于多实现同一接口但需不同依赖的场景,如 photocontroller 用 cloudfilesystem、videocontroller 用 localfilesystem。

Laravel 6 支持 when()->needs()->give() 这种上下文限定绑定,用于在特定类被解析时,为其构造函数中某个指定参数注入固定值或特定实例。它不改变类本身的绑定方式,而是“按需插值”,属于精准控制依赖注入的高级用法。
什么时候该用 when 绑定
当你有多个类实现同一个接口,但不同类需要不同的配置或依赖实例时。比如:
-
PhotoController需要用云存储CloudFilesystem -
VideoController却要用本地文件系统LocalFilesystem
而它们都依赖Filesystem接口。这时不能全局绑定一个实现,就得靠上下文限定。
基本写法与要点
在服务提供者的 register() 方法里写:
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(CloudFilesystem::class);
也可以注入原始值(如字符串、数字)或闭包:
$this->app->when(PaymentProcessor::class)
->needs('$mode')
->give('live');
$this->app->when(ReportGenerator::class)
->needs('$timeout')
->give(fn ($app) => config('reports.timeout'));
⚠️ 注意事项:
-
needs()中的参数名必须带$符号,且和目标类构造函数参数名完全一致(如function ($mode, $retryLimit)就得写needs('$mode')) - 只作用于目标类的直接构造参数,不会递归解析你
give()里返回的对象所依赖的其他类 -
give()传闭包时,每次解析都会执行一次,适合动态值;传类名则走容器标准解析流程 - 必须在
register()中注册,boot()太晚,绑定可能失效
和 bind / singleton 的关系
when 不是替代 bind 或 singleton,而是补充:
-
bind()决定“这个类怎么造” -
when()决定“在某个上下文中,给它的某个参数塞什么” - 三者可共存。例如
Filesystem接口本身没绑定,但通过when在不同控制器里分别注入不同实现,容器仍能正常解析。
调试小技巧
如果注入没生效,检查:
- 目标类是否真的通过
app()->make()或构造注入被容器解析(手动new不触发) - 参数名是否拼错,包括
$和大小写 - 是否在
register()里注册,而不是boot()或路由闭包里
本质上,when 是 Laravel 提供的一条“规则通道”,让容器在解析链中某一层精准干预参数,而不是粗粒度地换掉整个类。











