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
相关产品推荐
相关产品推荐

