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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 02:40:25