You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laminas应用集成Symfony Console:如何在工厂中获取控制台输出实例

解决方案

核心问题在于:Symfony Console的OutputInterface实例是在命令执行阶段(execute方法调用时)才被创建的,并非Laminas容器中的常驻服务,所以在构建Command的工厂阶段,这个实例还未生成,自然无法从容器获取。

要实现需求,只需将订阅者的绑定逻辑从工厂移至Command的execute方法中,此时已经能拿到Output实例,具体步骤如下:

1. 调整CliOutputFormatter,支持注入OutputInterface

让订阅者接收Output实例作为依赖,用于后续输出事件信息:

use Symfony\Component\Console\Output\OutputInterface;
use Laminas\EventManager\EventSubscriberInterface;

class CliOutputFormatter implements EventSubscriberInterface
{
    private OutputInterface $output;

    public function __construct(OutputInterface $output)
    {
        $this->output = $output;
    }

    // 实现事件处理方法,根据你的事件类型调整
    public function onComplexEvent(ComplexEvent $event): void
    {
        // 利用Output的格式化能力输出内容
        $this->output->writeln(sprintf('<info>事件通知:</info>%s', $event->getMessage()));
    }

    // 声明订阅的事件(根据你的事件名称调整)
    public static function getSubscribedEvents(): array
    {
        return [
            'complex.service.event' => 'onComplexEvent',
        ];
    }
}

2. 修改Command,在execute方法中绑定订阅者

在execute方法中获取Output实例,创建/获取CliOutputFormatter并附加到ComplexService:

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Laminas\ServiceManager\ContainerInterface;

class MyCliCommand extends Command
{
    private ComplexService $service;
    private ContainerInterface $container;

    // 注入容器,用于获取CliOutputFormatter(或直接注入其工厂)
    public function __construct(ComplexService $service, ContainerInterface $container)
    {
        parent::__construct();
        $this->service = $service;
        $this->container = $container;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // 创建CliOutputFormatter实例并传入Output
        $cliOutputFormatter = $this->container->get(CliOutputFormatter::class, ['output' => $output]);
        $this->service->attach($cliOutputFormatter);

        // 执行复杂逻辑
        $this->service->doComplexThings();

        $output->writeln("\nCli complete");
        return Command::SUCCESS;
    }
}

3. 配置CliOutputFormatter的工厂(可选,更符合DI规范)

如果希望通过Laminas的ServiceManager来创建CliOutputFormatter,可以定义一个专用工厂:

use Laminas\ServiceManager\FactoryInterface;
use Laminas\ServiceManager\ContainerInterface;
use Symfony\Component\Console\Output\OutputInterface;

class CliOutputFormatterFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null)
    {
        if (!isset($options['output']) || !$options['output'] instanceof OutputInterface) {
            throw new \InvalidArgumentException('必须传入有效的OutputInterface实例');
        }
        return new CliOutputFormatter($options['output']);
    }
}

然后在服务配置中注册:

// config/services.php
return [
    'factories' => [
        CliOutputFormatter::class => CliOutputFormatterFactory::class,
        // ...其他服务配置
    ],
];

4. 调整Command工厂,移除无效的绑定代码

原来的工厂中不再需要绑定CliOutputFormatter,改为注入容器:

use Laminas\ServiceManager\FactoryInterface;
use Laminas\ServiceManager\ContainerInterface;

class MyCliCommandFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null)
    {
        $complexService = $container->get(ComplexService::class);
        $complexService->attach($container->get(DbLogger::class));
        $complexService->attach($container->get(EmailNotifier::class));
        
        // 移除原来的CliOutputFormatter绑定代码
        return new MyCliCommand($complexService, $container);
    }
}

这样调整后,每次命令执行时,都会创建一个绑定了当前Output实例的CliOutputFormatter订阅者,事件信息就能通过Console的格式化功能输出到控制台了。

内容的提问来源于stack exchange,提问作者John Crest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:22:46