服务订阅者和定位器

编辑该页面

警告:你浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 4.1,不再维护。

这个页面的更新版本Symf欧宝娱乐app下载地址ony 6.2(当前的稳定版本)。

服务订阅者和定位器

有时,一个服务需要访问其他服务不相信他们会被使用。在这些情况下,您可能希望服务的实例化是懒惰。然而,那是不可能的使用显式的依赖注入自服务并非都是应该的懒惰的(见懒惰的服务)。

这种情况通常可以在你的控制器,你可以在构造函数中注入多个服务,但只使用了其中的一些执行的行动。另一个例子是应用程序实现命令模式使用CommandBus地图指挥命令处理程序的类名,使用它们来处理各自的命令时要求:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30
/ / src / CommandBus.php名称空间应用程序;/ /……CommandBus{/ * * *@varCommandHandler [] * /私人美元handlerMap;公共函数__construct(数组美元handlerMap){美元- >handlerMap =美元handlerMap;}公共函数处理(命令美元命令){美元commandClass= get_class (美元命令);如果(!收取(美元- >handlerMap [美元commandClass))){返回;}返回美元- >handlerMap [美元commandClass]- >处理(美元命令);}}/ /……美元commandBus- >处理(FooCommand ());

考虑到一次只处理一个命令,实例化所有其他命令处理程序是不必要的。延迟加载一个可能的解决方案处理程序可以将主要的依赖注入容器。

然而,注入整个容器是气馁,因为这给了太广泛的访问现有的服务和隐藏的实际依赖服务。这样做还需要服务公开,这并不是在Symfony应用程序默认的情况。欧宝娱乐app下载地址

服务订阅者旨在解决这个问题通过给获得一组预定义的服务而实例化它们只有当实际需要通过一个吗服务定位器,一个单独的延迟加载容器。

定义一个服务订阅者

首先,把CommandBus成的一个实现ServiceSubscriberInterface。使用它的getSubscribedServices ()方法包括尽可能多的服务需要在服务订阅者和改变容器的类型提示PSR-11ContainerInterface:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31 32 33 34 35 36
/ / src / CommandBus.php名称空间应用程序;使用应用程序\CommandHandler\BarHandler;使用应用程序\CommandHandler\FooHandler;使用Psr\容器\ContainerInterface;使用欧宝娱乐app下载地址\组件\DependencyInjection\ServiceSubscriberInterface;CommandBus实现了ServiceSubscriberInterface{私人美元定位器;公共函数__construct(ContainerInterface美元定位器){美元- >定位器=美元定位器;}公共静态函数getSubscribedServices(){返回(“App \ FooCommand”= > FooHandler::类,“App \ BarCommand”= > BarHandler::类);}公共函数处理(命令美元命令){美元commandClass= get_class (美元命令);如果(美元- >定位器- >有(美元commandClass)){美元处理程序=美元- >定位器- >get (美元commandClass);返回美元处理程序- >处理(美元命令);}}}

提示

如果容器包含订阅服务,仔细检查可以使用autoconfigure启用。你也可以手动添加container.service_subscriber标签。

注入的服务的一个实例ServiceLocator它实现了PSR-11ContainerInterface,但它也是一个可调用:

1 2 3 4
/ /……美元处理程序= (美元- >定位器)(美元commandClass);返回美元处理程序- >处理(美元命令);

包括服务

为了添加一个新的依赖服务用户,使用getSubscribedServices ()方法在服务定位器中添加服务类型包括:

1 2 3 4 5 6 7 8 9
使用Psr\日志\LoggerInterface;公共静态函数getSubscribedServices(){返回(/ /……LoggerInterface::类);}

服务类型也可以由一个服务名称为内部使用:

1 2 3 4 5 6 7 8 9
使用Psr\日志\LoggerInterface;公共静态函数getSubscribedServices(){返回(/ /……“日志”= > LoggerInterface::类);}

当扩展一个类,还实现了ServiceSubscriberInterface,这是你的责任时调用父重写该方法。这通常发生在扩展AbstractController:

1 2 3 4 5 6 7 8 9 10 11 12 13
使用Psr\日志\LoggerInterface;使用欧宝娱乐app下载地址\\FrameworkBundle\控制器\AbstractController;MyController扩展AbstractController{公共静态函数getSubscribedServices(){返回array_merge (::getSubscribedServices (), (/ /……“日志”= > LoggerInterface::类,]);}}

可选服务

可选依赖,预谋的服务类型吗?为了防止错误如果没有匹配的服务服务容器中发现:

1 2 3 4 5 6 7 8 9
使用Psr\日志\LoggerInterface;公共静态函数getSubscribedServices(){返回(/ /……“?”.LoggerInterface::类);}

请注意

确保存在一个可选的服务通过调用有()在调用服务定位器服务本身。

别名服务

默认情况下,自动装配用于匹配服务类型服务从服务容器。如果你不使用自动装配或需要添加一个非传统服务依赖关系,使用container.service_subscriber标记一个服务类型映射到一个服务。

  • YAML
  • XML
  • PHP
1 2 3 4 5
#配置/ services.yaml服务:App \ CommandBus:标签:- - - - - -{名称:“container.service_subscriber”,关键:“日志”,id:“monolog.logger.event”}

提示

关键属性可以省略,如果服务名称服务容器内部是一样的。

定义一个服务定位器

手动定义一个服务定位器,创建一个新的服务定义并添加container.service_locator标签。使用它的参数选项包括尽可能多的服务需要。

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11
#配置/ services.yaml服务:app.command_handler_locator:类:欧宝娱乐app下载地址Symfony \ \ DependencyInjection \ ServiceLocator组件参数:- - - - - -App \ FooCommand:“@app.command_handler.foo”App \ BarCommand:“@app.command_handler.bar”#如果你不使用默认服务自动配置,#添加以下标签服务定义:#标签(“container.service_locator”):

4.1

服务定位器自动配置是在Symfony 4.1中引入的。欧宝娱乐app下载地址在以前你总是需要添加Sy欧宝娱乐app下载地址mfony版本container.service_locator标记明确。

请注意

服务定位器参数中定义的服务必须包括钥匙,后来成为他们定位器内部的惟一标识符。

现在,您可以使用服务定位器通过注入它在任何其他服务:

  • YAML
  • XML
  • PHP
1 2 3 4
#配置/ services.yaml服务:App \ CommandBus:参数:(“@app.command_handler_locator”)

编译器推荐使用注册()方法来创建服务定位器。这将节省您的一些样板,将共享相同的定位器在所有服务引用:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
使用欧宝娱乐app下载地址\组件\DependencyInjection\编译器\ServiceLocatorTagPass;使用欧宝娱乐app下载地址\组件\DependencyInjection\ContainerBuilder;公共函数过程(ContainerBuilder美元容器){/ /……美元locateableServices= (/ /……“日志”= >引用(“日志”),);美元myService- >addArgument (ServiceLocatorTagPass::注册(美元容器,美元locateableServices));}
这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。