Symfony服务多方法共享进度条回调的优雅实现方案问询
优雅实现Symfony服务多方法共享进度回调的方案
方案1:给服务注入进度回调属性(推荐)
在服务类中定义私有属性存储回调,提供设置方法,命令中初始化ProgressBar后将更新逻辑以回调形式传入服务,服务内部所有方法直接调用该属性即可,无需逐个传参。
服务类示例
namespace App\Service; class YourProcessingService { /** @var callable|null */ private $progressCallback; public function setProgressCallback(callable $callback): void { $this->progressCallback = $callback; } private function updateProgress(): void { if ($this->progressCallback) { ($this->progressCallback)(); } } public function processFirstBatch(): void { // 执行第一批次操作 $this->updateProgress(); } public function processSecondBatch(): void { // 执行第二批次操作 $this->updateProgress(); } public function runFullProcess(): void { $this->processFirstBatch(); $this->processSecondBatch(); } }
命令类示例
namespace App\Command; use App\Service\YourProcessingService; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class DataProcessCommand extends Command { protected static $defaultName = 'app:process-data'; public function __construct(private YourProcessingService $processingService) { parent::__construct(); } protected function execute(InputInterface $input, OutputInterface $output): int { $totalSteps = 2; $progressBar = new ProgressBar($output, $totalSteps); $progressBar->start(); // 将进度更新逻辑传入服务 $this->processingService->setProgressCallback(function () use ($progressBar) { $progressBar->advance(); }); $this->processingService->runFullProcess(); $progressBar->finish(); $output->writeln(''); return Command::SUCCESS; } }
方案2:注入OutputInterface(命令专用服务)
如果该服务仅在命令上下文使用,可以直接注入OutputInterface,服务内部自行初始化和操作ProgressBar,彻底避免回调传递。缺点是服务会依赖Console组件,无法在非命令场景复用。
服务类示例
namespace App\Service; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Output\OutputInterface; class CommandOnlyProcessor { private ?ProgressBar $progressBar = null; public function __construct(private OutputInterface $output) { } public function initProgress(int $totalSteps): void { $this->progressBar = new ProgressBar($this->output, $totalSteps); $this->progressBar->start(); } private function advanceProgress(): void { if ($this->progressBar) { $this->progressBar->advance(); } } public function processFirstStage(): void { // 执行第一阶段操作 $this->advanceProgress(); } public function processSecondStage(): void { // 执行第二阶段操作 $this->advanceProgress(); } public function finishProgress(): void { if ($this->progressBar) { $this->progressBar->finish(); } } }
命令类示例
namespace App\Command; use App\Service\CommandOnlyProcessor; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class QuickProcessCommand extends Command { protected static $defaultName = 'app:quick-process'; public function __construct(private CommandOnlyProcessor $processor) { parent::__construct(); } protected function execute(InputInterface $input, OutputInterface $output): int { $this->processor->initProgress(2); $this->processor->processFirstStage(); $this->processor->processSecondStage(); $this->processor->finishProgress(); $output->writeln(''); return Command::SUCCESS; } }
方案3:事件驱动(高解耦场景)
通过定义进度事件,服务仅负责触发事件,命令端监听事件并更新ProgressBar。这种方式完全解耦服务与Console组件,适合复杂流程或需要多端监听进度的场景。
进度事件定义
namespace App\Event; use Symfony\Contracts\EventDispatcher\Event; class ProgressAdvanceEvent extends Event { // 可按需添加步骤、总进度等参数 }
服务类示例
namespace App\Service; use App\Event\ProgressAdvanceEvent; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class DecoupledProcessor { public function __construct(private EventDispatcherInterface $eventDispatcher) { } private function triggerProgress(): void { $this->eventDispatcher->dispatch(new ProgressAdvanceEvent()); } public function processFirstTask(): void { // 执行任务逻辑 $this->triggerProgress(); } public function processSecondTask(): void { // 执行任务逻辑 $this->triggerProgress(); } }
命令类示例
namespace App\Command; use App\Event\ProgressAdvanceEvent; use App\Service\DecoupledProcessor; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class DecoupledProcessCommand extends Command { protected static $defaultName = 'app:decoupled-process'; public function __construct( private DecoupledProcessor $processor, private EventDispatcherInterface $eventDispatcher ) { parent::__construct(); } protected function execute(InputInterface $input, OutputInterface $output): int { $totalSteps = 2; $progressBar = new ProgressBar($output, $totalSteps); $progressBar->start(); // 监听进度事件 $listener = function () use ($progressBar) { $progressBar->advance(); }; $this->eventDispatcher->addListener(ProgressAdvanceEvent::class, $listener); $this->processor->processFirstTask(); $this->processor->processSecondTask(); // 清理监听 $this->eventDispatcher->removeListener(ProgressAdvanceEvent::class, $listener); $progressBar->finish(); $output->writeln(''); return Command::SUCCESS; } }
内容的提问来源于stack exchange,提问作者Tomasz Filipek
相关产品推荐
相关产品推荐

