Php Symfony 3服务依赖于另一服务的未知数量。如何实施?
我对Symfony相当陌生,但对PHP很有经验。假设我有一个服务,它需要另一个未知数量的服务。注射它是没有意义的(我会注射多少)。我可以使用Php Symfony 3服务依赖于另一服务的未知数量。如何实施?,php,symfony,Php,Symfony,我对Symfony相当陌生,但对PHP很有经验。假设我有一个服务,它需要另一个未知数量的服务。注射它是没有意义的(我会注射多少)。我可以使用ContainerAwareInterface和ContainerAwareTrait,但我已经读到了这一点 稍微做作的例子: class ProcessBuilder { private $allCommands = []; public function build(array $config){ foreach ($c
ContainerAwareInterface
和ContainerAwareTrait
,但我已经读到了这一点
稍微做作的例子:
class ProcessBuilder {
private $allCommands = [];
public function build(array $config){
foreach ($config => $command){
$this->allCommands[] = $this->getContainer()->get('app.worker.command')->init($command);
}
}
}
在获取我的ProcessBuilder
服务时,我不知道$config
数组中将有多少项传递到build()
。由于命令
类(app.worker.Command
服务)的工作方式,它们不能共享单个实例
最好的方法是什么?或者我需要走containerware*
路线吗
我希望这是有道理的,谢谢你的帮助。如果以前有人问过这个问题,我很抱歉,但我在谷歌上搜索得很好,什么都没找到。你走的方向是正确的。现在唯一正确的地方不见了 要收集特定类型的服务,我们需要领先一步。到依赖注入容器编译(这就是Symfony收集
EventSubscriber
类型或Voter
类型服务的方式。)
您可以使用扩展注册服务,并使用CompilerPass以任何方式操作它们
例子
这是
你的案子通过了吗
如果我们将您的代码转换为编译器过程,它将如下所示:
ProcessBuilder.php
class ProcessBuilder
{
/**
* @var CommandInterface[]
*/
private $allCommands = [];
public function addCommand(CommandInterface $command)
{
$this->allCommands[] = $command
}
}
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
final class AddCommandsToProcessBuilderCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $containerBuilder): void
{
# using Symfony 3.3+ class name, you can use string name as well
$processBuilderDefinition = $this->containerBuilder->getDefinition(ProcessBuilder::class);
foreach ($this->containerBuilder->getDefinitions() as $serviceName => $definition) {
if (is_subclass_of($definition->getClass(), CommandInterface::class)) {
$processBuilderDefinition->addMethodCall('addCommand', [new Reference($serviceName)]);
}
}
}
}
use Symfony\Component\HttpKernel\Bundle\Bundle;
final class AppBundle extends Bundle
{
public function build(ContainerBuilder $containerBuilder): void
{
$containerBuilder->addCompilerPass(new AddCommandsToProcessBuilderCompilerPass);
}
}
addCommandStopProcessBuilderCompilerPass.php
class ProcessBuilder
{
/**
* @var CommandInterface[]
*/
private $allCommands = [];
public function addCommand(CommandInterface $command)
{
$this->allCommands[] = $command
}
}
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
final class AddCommandsToProcessBuilderCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $containerBuilder): void
{
# using Symfony 3.3+ class name, you can use string name as well
$processBuilderDefinition = $this->containerBuilder->getDefinition(ProcessBuilder::class);
foreach ($this->containerBuilder->getDefinitions() as $serviceName => $definition) {
if (is_subclass_of($definition->getClass(), CommandInterface::class)) {
$processBuilderDefinition->addMethodCall('addCommand', [new Reference($serviceName)]);
}
}
}
}
use Symfony\Component\HttpKernel\Bundle\Bundle;
final class AppBundle extends Bundle
{
public function build(ContainerBuilder $containerBuilder): void
{
$containerBuilder->addCompilerPass(new AddCommandsToProcessBuilderCompilerPass);
}
}
AppBundle.php
class ProcessBuilder
{
/**
* @var CommandInterface[]
*/
private $allCommands = [];
public function addCommand(CommandInterface $command)
{
$this->allCommands[] = $command
}
}
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
final class AddCommandsToProcessBuilderCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $containerBuilder): void
{
# using Symfony 3.3+ class name, you can use string name as well
$processBuilderDefinition = $this->containerBuilder->getDefinition(ProcessBuilder::class);
foreach ($this->containerBuilder->getDefinitions() as $serviceName => $definition) {
if (is_subclass_of($definition->getClass(), CommandInterface::class)) {
$processBuilderDefinition->addMethodCall('addCommand', [new Reference($serviceName)]);
}
}
}
}
use Symfony\Component\HttpKernel\Bundle\Bundle;
final class AppBundle extends Bundle
{
public function build(ContainerBuilder $containerBuilder): void
{
$containerBuilder->addCompilerPass(new AddCommandsToProcessBuilderCompilerPass);
}
}
并将包添加到AppKernel.php
:
final class AppKernel extends Kernel
{
public function registerBundles()
{
bundles = [];
$bundles[] = new AppBundle;
}
}
这是在Symfony以干净的方式完成您需要的全部过程。也许这就是您需要的?或者另一种方法是。您应该传递命令服务工厂实例,而不是命令服务实例。这是一个非常干净的解决方案@dragoste-出于好奇,您的工厂如何知道要使用哪些服务?@Cerad问题是特定服务的实例数量可变,而不是要注入哪个服务。@dragoste我认为问题是如何将数量可变的命令服务注入某种命令调度程序。但我很可能错了。