在 Symfony 命令行中解耦输出

Decoupling output in Symfony command line

Note: I refer to the Symfony Console component quite a lot in my question, but I think this question could be considered broader if thought about in the context of any user interface.

我正在使用 Symfony Console component 创建控制台应用程序。我试图将 class 耦合保持在最低限度,因为它使单元测试更容易并且通常是更好的做法。

我的应用程序有一些过程可能需要一些时间才能完成,所以我想在运行时使用进度条和一般文本输出让用户了解正在发生的事情。 Symfony 需要将 Symfony 控制台输出接口的实例传递给任何命令的执行方法。到目前为止,一切都很好;我可以随心所欲地创建进度条和输出文本。但是,我的应用程序的所有繁重工作都不会发生在命令的执行方法中,而是发生在我的应用程序的核心 classes 中。这些 class 不应该也不知道它们正在控制台应用程序中使用。

我正在努力保持这种状态,因为我不知道如何在不将输出 class 注入我的核心的情况下向控制台(或任何用户界面)提供反馈。这样做会导致控制台输出 class 和我的应用程序核心之间的紧密耦合。我考虑过使用事件调度程序(Symfony 有一个),但这也意味着我的核心将与调度程序耦合(也许这很好)。理想情况下,我需要将我的应用程序状态排序为 "bubble" 返回到调用命令的执行方法,然后我可以在其中执行输出。

有人能给我指出正确的方向吗?我觉得这实际上一定是很常见的情况,但找不到太多相关信息。

提前感谢您抽出时间!

我以前成功使用过事件派发器方法。例如,您可以在处理的开始、进度和结束时触发事件,并让事件侦听器基于此更新进度条。

<?php

$progress = $this->getHelperSet()->get('progress');
$dispatcher = $this->getContainer()->get('event_dispatcher');

$dispatcher->addListener('my_start_event', function (GenericEvent $event) use ($progress, $output) {
    $progress->start($output, $event->getArgument('total'));
});

$dispatcher->addListener('my_progress_event', function () use ($progress) {
    $progress->advance();
});

$dispatcher->addListener('my_finish_event', function () use ($progress) {
    $progress->finish();
});

如果您真的想避免在您的服务中耦合事件调度程序,您可以扩展或修饰您的 class(可能实现共享接口),并且只在那里使用事件调度程序。但是,您需要在基 class 中有一个扩展点(public 或受保护的方法)才能通知任何进度。