laravel 6 中服务容器的 tag 功能用于为多个绑定打相同标签并批量解析,需先 bind 再 tag,通过 tagged('tag-name') 获取实例数组,支持接口抽象与依赖自动注入,标签仅作分组不参与解析。

在 Laravel 6 中,服务容器的 tag 功能允许你为多个绑定打上相同标签,然后一次性解析全部,适合需要统一管理、批量注入或遍历执行的场景(比如事件监听器、策略处理器、日志通道等)。
怎么给服务类打 tag
在服务提供者的 register() 方法中,使用 $this->app->tag() 方法为已绑定的服务添加标签。注意:必须先绑定,再打标。
- 先绑定具体实现(支持接口绑定、闭包绑定、类名绑定)
- 再用
tag()指定抽象标识和标签名
示例:
// AppServiceProvider@register()
$this->app->bind('payment.processor.alipay', function ($app) {
return new AlipayProcessor($app->make('config'));
});
$this->app->bind('payment.processor.wechat', function ($app) {
return new WechatProcessor($app->make('config'));
});
$this->app->bind('payment.processor.stripe', function ($app) {
return new StripeProcessor($app->make('config'));
});
// 统一打上 'payment-processor' 标签
$this->app->tag(['payment.processor.alipay', 'payment.processor.wechat', 'payment.processor.stripe'], 'payment-processor');
如何批量解析带 tag 的服务
使用 $this->app->tagged('tag-name') 方法,返回一个包含所有该标签下已解析实例的数组,每个元素都是对应服务的完整对象。
- 返回值是
array,不是 Collection,如需链式操作可自行 wrap - 解析过程会触发各服务的完整依赖注入(包括构造函数依赖递归解析)
- 若某服务尚未被解析过,
tagged()会按需自动make()它
典型用法:
// 在控制器或服务中
$processors = $this->app->tagged('payment-processor');
foreach ($processors as $processor) {
if ($processor->supports($order->currency)) {
return $processor->charge($order);
}
}
配合接口绑定 + tag 更灵活
推荐结合接口抽象使用,便于扩展和测试:
- 定义统一接口:
PaymentProcessor - 绑定多个实现到该接口,并分别打 tag
- 解析时仍用
tagged(),但类型安全更高
示例:
$this->app->bind(PaymentProcessor::class, AlipayProcessor::class)->tag('payment-processor');
$this->app->bind(PaymentProcessor::class, WechatProcessor::class)->tag('payment-processor');
// 注意:这里实际注册的是两个不同实现,tag 是附加元信息,不冲突
此时 $this->app->tagged('payment-processor') 返回的仍是两个独立实例,各自完成构造与依赖注入。
注意事项
- 标签本身不参与解析逻辑,只是“分组标记”,不能直接
make('payment-processor') - 不要对未绑定的服务打 tag,否则
tagged()返回空数组且无报错 - Laravel 6 不支持
when(...)->needs(...)->give(...)与 tag 联动,条件绑定需单独处理 - 单元测试中若修改了 tagged 实例的状态,建议手动
$this->app->forgetInstance()避免污染











