Progress Bar(进度条)

3.4 版本
维护中的版本

当执行长时间运行的命令时,显示进度信息可能是有益的,它会在你的命令运行时更新:

要显示进度细节,使用 ProgressBar,传给它一个单元(unit)总数,然后在命令执行时,推进(advance)进度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use Symfony\Component\Console\Helper\ProgressBar;
 
// create a new progress bar (50 units)
// 创建一个新的进度条(50单元)
$progress = new ProgressBar($output, 50);
 
// start and displays the progress bar
// 启动并显示进度条
$progress->start();
 
$i = 0;
while ($i++ < 50) {
    // ... do some work / 做一些事
 
    // advance the progress bar 1 unit
    // 推进进度条一个单位
    $progress->advance();
 
    // you can also advance the progress bar by more than 1 unit
    // 你也可以用一个以上的单位来推进进度条
    // $progress->advance(3);
}
 
// ensure that the progress bar is at 100%
// 确保进度条达到100%
$progress->finish();

不同于使用步数来推进条子 (即使用 advance() 方法),你还可以通过 setProgress() 方法来设置当前的总进度。

如果你的系统不支持 ANSI codes,更新进度条时会添加一个新行。要防止output溢出,调整相应的 setRedrawFrequency()。默认时,当使用 max时,重绘频率(redraw frequency)被设为你的 max 值的 10%

如果你不知道要推进的总步数,在创建 ProgressBar 实例时可直接忽略step参数:

1
$progress = new ProgressBar($output);

这时进度将被动态显示:

1
2
3
4
5
6
7
8
9
10
# no max steps (displays it like a throbber)
# 不提供最大步数时(动态指示)
    0 [>---------------------------]
    5 [----->----------------------]
    5 [============================]
 
# max steps defined / 定义了max steps时
 0/3 [>---------------------------]   0%
 1/3 [=========>------------------]  33%
 3/3 [============================] 100%

当任务完成,不要忘记调用 finish() 以便进度条的显示被刷新为100%的完成度。

如果你希望在进度条运行时,输出一些东西,首先调用 clear() 。然后调用 display() 来重新显示进度条。

自定义进度条 

内置的格式 

默认时,在进度条上渲染的信息取决于当前 OutputInterface 实例的冗长度级别(verbosity level):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# OutputInterface::VERBOSITY_NORMAL (CLI with no verbosity flag)
 0/3 [>---------------------------]   0%
 1/3 [=========>------------------]  33%
 3/3 [============================] 100%
 
# OutputInterface::VERBOSITY_VERBOSE (-v)
 0/3 [>---------------------------]   0%  1 sec
 1/3 [=========>------------------]  33%  1 sec
 3/3 [============================] 100%  1 sec
 
# OutputInterface::VERBOSITY_VERY_VERBOSE (-vv)
 0/3 [>---------------------------]   0%  1 sec
 1/3 [=========>------------------]  33%  1 sec
 3/3 [============================] 100%  1 sec
 
# OutputInterface::VERBOSITY_DEBUG (-vvv)
 0/3 [>---------------------------]   0%  1 sec/1 sec  1.0 MB
 1/3 [=========>------------------]  33%  1 sec/1 sec  1.0 MB
 3/3 [============================] 100%  1 sec/1 sec  1.0 MB

如果你使用静默旗标(-q)来调用命令,进度条将不被显示。

若不想受到当前命令的冗长模式约束,你还可以通过 setFormat() 来强制格式输出:

1
$bar->setFormat('verbose');

有以下内置格式:

  • normal
  • verbose
  • very_verbose
  • debug

如果你没有设置进度条的总步数,使用 _nomax 变体:

  • normal_nomax
  • verbose_nomax
  • very_verbose_nomax
  • debug_nomax

自定义格式 

不使用内置格式(built-in formats)时,可以设置你自己的:

1
$bar->setFormat('%bar%');

它设置的是只显示进度条本身

1
2
3
>---------------------------
=========>------------------
============================

进度条格式(prgress bar format),就是包含了特定占位符(被 % 括起的名称)的一个字符串;占位符将根据条子的当前进度被替换掉。以下是内置占位符的列表:

  • current: The current step(当前步数);
  • max: 最大步数 (未定义时是0);
  • bar: 条子本身;
  • percent: 进度完成的百分比 (max未定义时不可用);
  • elapsed: 启动进度条后流经的时间;
  • remaining: 完成任务的剩余时间 (max未定义时不可用);
  • estimated: 预期的完成任务时间 (max未定义时不可用);
  • memory: 当前内存占用;
  • message: 当前进度条上的附加信息

例如,这里有一个如何去设置一个和 debug 相同的格式之样例:

1
$bar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%');

注意到被添加到某些占位符的 :6s 部分了吗?这就是你如何去调整条子外观 (包括格式和排列等)的方法。冒号 (:) 后面的部分用于设置字符串的 sprintf 格式。

message 占位符有些特殊,因为你必须自行设置它的值:

1
2
3
4
5
6
7
8
9
10
$bar->setMessage('Task starts');
$bar->start();
 
$bar->setMessage('Task in progress...');
$bar->advance();
 
// ...
 
$bar->setMessage('Task is finished');
$bar->finish();

若不想对给定的进度条实例去设置格式,你可以设置全局格式(global formats):

1
2
3
4
ProgressBar::setFormatDefinition('minimal', 'Progress: %percent%%');
 
$bar = new ProgressBar($output, 3);
$bar->setFormat('minimal');

以上代码定义了一个全新的 minimal 格式,你可以用在自己的进度条中:

1
2
3
Progress: 0%
Progress: 33%
Progress: 100%

重新的定义内置格式总是好过自行创造一种。因为它可以让你基于“命令的冗长级别旗标”来自动进行多样化显示。

要定义一个包含了“最大步数已知时才可用”的占位符之全新风格时,你应该创建一个 _nomax 变体:

1
2
3
4
5
ProgressBar::setFormatDefinition('minimal', '%percent%% %remaining%');
ProgressBar::setFormatDefinition('minimal_nomax', '%percent%%');
 
$bar = new ProgressBar($output);
$bar->setFormat('minimal');

显示进度条时,该格式将被自动设置为 minimal_nomax,如果条子并没有一个“最大步数”的话,就像上例中的代码。

一个格式(formata)可以包含任何有效的ANSI字符,也可以使用Symfony的特定方式来设置颜色:

1
2
3
4
ProgressBar::setFormatDefinition(
    'minimal',
    '<info>%percent%</info>\033[32m%\033[0m <fg=white;bg=blue>%remaining%</>'
);

一个格式,可以扩展为多行;当你希望在进度条旁边显示更多的上下文信息时,这特别有用(参考本文开头部分)。

条子设置 

在所有占位符中,bar 有点特殊,因为所有用于显示它的占位符都可以被自定义:

1
2
3
4
5
6
7
8
9
10
11
// the finished part of the bar / 条子的已完成部分
$progress->setBarCharacter('<comment>=</comment>');
 
// the unfinished part of the bar / 条子的未完成部分
$progress->setEmptyBarCharacter(' ');
 
// the progress character / 进度之字符
$progress->setProgressCharacter('|');
 
// the bar width / 条子宽度
$progress->setBarWidth(50);

出于性能原因,在设置较高数值的总步数时要小心。例如,如果你遍历的是大量元素,考虑调用 setRedrawFrequency() 来将重绘频率设为一个高值,以便它只在少量的循环中被更新: so it updates on only some iterations:

1
2
3
4
5
6
7
8
9
10
11
12
$progress = new ProgressBar($output, 50000);
$progress->start();
 
// update every 100 iterations / 每100次循环更新一次
$progress->setRedrawFrequency(100);
 
$i = 0;
while ($i++ < 50000) {
    // ... do some work / 处理一些事
 
    $progress->advance();
}

自定义占位符 

如果你希望显示一些取决于 “在内置占位符列表中不可用” 的进度条显示 之信息,你可以创建自己的。看一下如何创建 remaining_steps 占位符,用来显示剩余的步数:

1
2
3
4
5
6
ProgressBar::setPlaceholderFormatterDefinition(
    'remaining_steps',
    function (ProgressBar $bar, OutputInterface $output) {
        return $bar->getMaxSteps() - $bar->getProgress();
    }
);

自定义消息 

%message% 占位符允许你指定一个自定义消息,它会和进度条一起显示出来。但如果你需要更多条消息,只需定义你自己的:

1
2
3
4
5
6
7
8
9
10
11
12
13
$bar->setMessage('Task starts');
$bar->setMessage('', 'filename');
$bar->start();
 
$bar->setMessage('Task is in progress...');
while ($file = array_pop($files)) {
    $bar->setMessage($filename, 'filename');
    $bar->advance();
}
 
$bar->setMessage('Task is finished');
$bar->setMessage('', 'filename');
$bar->finish();

对于让 filename 成为进度条的一部分,只需添加 %filename% 占位符到你的format中:

1
$bar->setFormat(" %message%\n %current%/%max%\n Working on %filename%");

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)