Symfony中命令调度模式下如何为自定义Handler自动注入依赖服务
实现方案
你需要借助Symfony的依赖注入容器能力替换掉手动new实例的逻辑,有两种常用实现方式:
方案1:直接使用全局服务容器
修改HandlerResolver,注入Symfony的全局容器,由容器负责创建Handler实例,自动解析注入构造参数依赖:
<?php use Psr\Container\ContainerInterface; class HandlerResolver { public function __construct( private ContainerInterface $container ) { } public function resolve(CommandInterface $command): AbstractHandler { $handlerClass = preg_replace('/Command/', 'Handler', $command::class); // 容器会自动解析构造参数的类型提示,注入已声明的对应服务 return $this->container->get($handlerClass); } }
注意:该方案需要将所有Handler类配置为容器可访问的服务,如果你开启了默认的
autowire/autoconfigure,只需要在config/services.yaml中添加配置将Handler标记为公共服务即可:services: App\Handler\: resource: '../src/Handler/*' public: true
方案2:使用专属服务定位器(更符合Symfony最佳实践)
该方案不会将Handler暴露到全局公共服务列表,权限管控更合理:
- 先新增一个标记接口,用于识别所有Handler类
<?php // 放在你自己的接口目录下即可 interface CommandHandlerInterface { }
- 让抽象Handler实现该标记接口
abstract class AbstractHandler implements CommandHandlerInterface { // 原有代码无需修改 }
- 修改
config/services.yaml配置,给所有Handler打标签并创建专属服务定位器
services: # 自动加载所有Handler,开启自动注入 App\Handler\: resource: '../src/Handler/*' autowire: true autoconfigure: true # 给所有实现标记接口的类自动打标签 _instanceof: App\Contract\CommandHandlerInterface: tags: ['app.command_handler'] # 为HandlerResolver注入专属服务定位器,包含所有打了标签的Handler App\Resolver\HandlerResolver: arguments: $handlerLocator: !tagged_locator { tag: 'app.command_handler' }
- 修改
HandlerResolver代码,使用专属定位器获取Handler实例
<?php use Psr\Container\ContainerInterface; class HandlerResolver { public function __construct( // 注入的是只包含所有Handler的专属定位器 private ContainerInterface $handlerLocator ) { } public function resolve(CommandInterface $command): AbstractHandler { $handlerClass = preg_replace('/Command/', 'Handler', $command::class); return $this->handlerLocator->get($handlerClass); } }
注意事项
只要你开启了Symfony默认的autowire配置,所有Handler构造函数中类型声明的服务,Symfony都会自动匹配注入,不需要额外手动配置。如果Handler有非服务类型的构造参数,可以在services.yaml中对应Handler的配置条目下手动指定参数值即可。
内容的提问来源于stack exchange,提问作者Baptiste Vadé
相关产品推荐
相关产品推荐

