Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何注入一组实现相同接口的服务,而不声明每个服务的连接?_Php_Symfony_Dependency Injection - Fatal编程技术网

Php 如何注入一组实现相同接口的服务,而不声明每个服务的连接?

Php 如何注入一组实现相同接口的服务,而不声明每个服务的连接?,php,symfony,dependency-injection,Php,Symfony,Dependency Injection,我正在开发一个应用程序,其中有一些处理程序作为我希望能够调用的服务。它们都实现了一个ItemHandlerInterface 我希望能够在控制器中检索所有ItemHandlerInterface服务集合,而无需手动接线 到目前为止,我专门给它们贴上了标签: 服务。yaml \u实例: App\Model\ItemHandlerInterface: 标记:[!php/const-App\DependencyInjection\ItemHandlersCompilerPass::ITEM\u-HAN

我正在开发一个应用程序,其中有一些处理程序作为我希望能够调用的服务。它们都实现了一个
ItemHandlerInterface

我希望能够在控制器中检索所有
ItemHandlerInterface
服务集合
,而无需手动接线

到目前为止,我专门给它们贴上了标签:

服务。yaml

\u实例:
App\Model\ItemHandlerInterface:
标记:[!php/const-App\DependencyInjection\ItemHandlersCompilerPass::ITEM\u-HANDLER\u标记]
懒惰:是的
并尝试在控制器中检索我的服务集合。如果只有一个服务实现了
ItemHandlerInterface
,它就可以工作了,但只要我创建了几个(如下面的
TestHandler
Test2Handler
),我就会得到一个
服务“service\u locator.03wqafw.App\Controller\itemUpdateControl”依赖于不存在的服务“App\Model\ItemHandlerInterface”。

如何动态检索实现我的接口的所有服务?

一个肮脏的解决方案是强制所有
ItemHandlerInterface
使用
public:true
并将
Container
传递给我的控制器构造函数。但这很难看,我想找到一种更优雅的方法

itemUpdateControl

namespace-App\Controller;
使用App\Model\ItemHandlerInterface;
使用App\Service\ItemFinder;
使用Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
使用Symfony\Component\Debug\Exception\ClassNotFoundException;
使用Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
使用Symfony\Component\HttpFoundation\RequestStack;
使用App\Model\Item;
使用Psr\Container\ContainerInterface;
/**
*类ItemUpdateControl
*
*@package-App\Controller
*/
类ItemUpdateControl扩展了AbstractController
{
/**
*@var容器接口
*/
受保护的$定位器;
公共函数构造(ContainerInterface$locator)
{
$this->locator=$locator;
}
公共静态函数getSubscribedServices()
{
//尝试订阅所有ItemHandlerInterface服务
返回数组合并(
父级::getSubscribedServices(),
['item\u handler'=>ItemHandlerInterface::class]
);
}
/**
*@param字符串$id
*@param RequestStack$RequestStack
*@param ItemFinder$ItemFinder
*
*@归还物品
*@throws\Symfony\Component\Debug\Exception\ClassNotFoundException
*/
公共函数调用(
字符串$id,
RequestStack$RequestStack,
ItemFinder$ItemFinder
) {
//查找项目
$item=$itemFinder->findById($id);
//提取并创建处理程序实例
$handlerName=$item->getHandlerName();
如果($this->locator->has($handlerName)){
$handler=$this->locator->get($handlerName);
$request=$requestStack->getCurrentRequest();
$payload=json_decode($request->getContent());
调用用户函数($handler,$payload,$request);
返回$item;
}
}
}
src/ItemHandler/TestHandler.php

namespace-App\ItemHandler;
使用App\Model\ItemHandlerInterface;
使用条令\ORM\EntityManagerInterface;
类TestHandler实现ItemHandlerInterface
{
//实施
}
src/ItemHandler/Test2Handler.php

namespace-App\ItemHandler;
使用App\Model\ItemHandlerInterface;
使用条令\ORM\EntityManagerInterface;
类Test2Handler实现ItemHandlerInterface
{
//实施
}

这样做的一个好方法是使用收集所有标记的服务,并将结果作为控制器的参数插入。
通过该类,您可以访问查找服务所需的所有方法(例如使用
findTaggedServiceIds

在内部经常使用此技巧,甚至有一个预先制作的编译器传递,它以抽象的方式执行此操作(因此您可以检查它是如何在内部完成的)。
要使用它,我们只需创建一个新的,扩展这个,并使用正确的参数调用父
\uu construct()
。()

在那里查看:


您可以一次性注入所有标记的服务,而无需使用编译器过程

配置 由于您已经在进行标记,如问题所示,只需声明注入:

_instanceof:
    App\Model\ItemHandlerInterface:
        tags: ['item_handler']
        lazy: true

services:
    App\Controller\ItemUpdateController:
        arguments: !tagged 'item_handler'
实施 您需要更改控制器的构造函数,以便它接受
iterable

public function\uuu构造(iterable$itemHandler)
{
$this->handlers=$itemHandlers;
}
在您的类中,a
RewindableGenerator
将与您的服务一起注入。您只需对其进行迭代即可获得其中的每一项

这是可用的;而且是可用的


额外的 从4.3开始,您可以使用带标签的服务定位器来实现这一点。配置同样简单,但您可以延迟实例化服务,而不必一开始就实例化所有服务


您可以阅读更多内容。

当我键入此内容时,我刚刚看到一个答案被接受。这很公平。无论如何,这是有效的,我现在将其作为参考:

services:
   _instanceof:
        # Tag all your item handlers
        App\Model\ItemHandlerInterface:
            tags: [app.item_handler]

    # inject as an iterable into the controller
    App\Controller\IndexController:
        arguments: [!tagged app.item_handler]
与接受答案相同的参考:


我还想指出,这种方法只支持iterable如果不实例化其余的,那么您需要使您的类更费劲。

不确定如果没有某种ItemHandlers定位器类,这将如何工作。Symfony如何知道将哪个定位器注入控制器?