php – Symfony – 通过可迭代注入标记服务的类名获取服务

我正在努力通过注入标记服务组的类名来获取特定服务.

这是一个例子:
标记了实现DriverInterface’app.driver’的所有服务,并将其绑定到$drivers变量.

在其他一些服务中,我需要获取所有标记为“app.driver”的驱动程序并实例化并仅使用其中的少数几个.但是需要什么驱动力是动态的.

services.yml

_defaults:
        autowire: true
        autoconfigure: true
        public: false
        bind:
            $drivers: [!tagged app.driver]

_instanceof:
        DriverInterface:
            tags: ['app.driver']

其他一些服务:

/**
 * @var iterable
 */
private $drivers;

/**
 * @param iterable $drivers
 */
public function __construct(iterable $drivers) 
{
    $this->drivers = $drivers;
}

public function getDriverByClassName(string $className): DriverInterface
{
    ????????
}

因此,实现Driver接口的服务被注入$this-> drivers param作为可迭代结果.我只能通过它们进行预告,但随后将实例化所有服务.

有没有其他方法来注入这些服务以通过类名从中获取特定服务而无需实例化其他服务?

附:我知道有可能将这些驱动程序公开并使用容器代替,但是如果可以采用其他方法,我希望避免将硬币注入服务中.

解决方法:

ServiceLocator将允许按名称访问服务,而无需实例化其余部分.它确实需要编译器通过,但它不是很难设置.

use Symfony\Component\DependencyInjection\ServiceLocator;
class DriverLocator extends ServiceLocator
{
    // Leave empty
}
# Some Service
public function __construct(DriverLocator $driverLocator) 
{
    $this->driverLocator = $driverLocator;
}

public function getDriverByClassName(string $className): DriverInterface
{
    return $this->driverLocator->get($fullyQualifiedClassName);
}

现在来了魔术:

# src/Kernel.PHP
# Make your kernel a compiler pass
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class Kernel extends BaseKernel implements CompilerPassInterface {
...
# Dynamically add all drivers to the locator using a compiler pass
public function process(ContainerBuilder $container)
{
    $driverIds = [];
    foreach ($container->findTaggedServiceIds('app.driver') as $id => $tags) {
        $driverIds[$id] = new Reference($id);
    }
    $driverLocator = $container->getDeFinition(DriverLocator::class);
    $driverLocator->setArguments([$driverIds]);
}

并且presto.假设您修复了我可能已经介绍的任何语法错误或拼写错误,它应该可以工作.

此外,您还可以自动注册驱动程序类并删除服务文件中的instanceof条目.

# Kernel.PHP
protected function build(ContainerBuilder $container)
{
    $container->registerForAutoconfiguration(DriverInterface::class)
        ->addTag('app.driver');
}

相关文章

统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
前言 之前做了微信登录,所以总结一下微信授权登录并获取用户...
FastAdmin是我第一个接触的后台管理系统框架。FastAdmin是一...
之前公司需要一个内部的通讯软件,就叫我做一个。通讯软件嘛...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...