看一眼你为自己的Symfony程序所开发的任何一个“命令行”代码。很大概率是,代码“一团糟”——混合着内容和表现层。例如,为了显示命令行的output的标题,你可能使用了下面几种常见方法之一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// alternative 1 方案1
$formatter = $this->getHelperSet()->get('formatter');
$formattedBlock = $formatter->formatBlock('Lorem Ipsum Dolor Sit Amet', '', true);
$output->writeln($formattedBlock);
 
// alternative 2 方案2
$title = 'Lorem Ipsum Dolor Sit Amet';
$output->writeln('<info>'.$title.'</info>');
$output->writeln(str_repeat('=', strlen($title)));
 
// alternative 3 方案3
$output->writeln('');
$output->writeln('<info>Lorem Ipsum Dolor Sit Amet</>');
$output->writeln('<info>-- -- -- -- -- -- --</>');
$output->writeln('');

几个月之前,我们决定改善这种情形,办法是引入一个全新的Symfony命令行样式向导(style guide)。样式已经在Symfony2.7中可用,但我们真正开始使用它们还是在2.8中。用一个网络程序进行类比,这些样式允许你创建语义化、忘掉其样式及行为的console命令。好比你的命令只需定义“HTML”,然后样式向导就是把它转化成现实的“bootstrap和jquery”。

在command程序中使用这个新的样式向导是相当容易的,实例化SymfonyStyle类,把你命令的$input$output传给它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace AppBundle\Command;
 
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
 
class MyCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        // ...
    }
 
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);
        // ...
    }
}

我们推荐你把这个变量命名为$io,因为你既可以在input也可以在output操作中使用它。依上面例程,以下演示了如何在你的命令中输出一个标题:

1
$io->title('Lorem Ipsum Dolor Sit Amet');

Symfony会帮你照顾样式细节:它会改变字体颜色,还能在标题的前后添加一个新行(new line),并对标题显示下划线。

样式向导包括了大量常用的快捷方法,例如要显示一个表格时:

1
2
3
4
5
6
7
$headers = ['Parameter', 'Value'];
$rows = [
    ['Param1', 'Value1'],
    ['Param2', 'Value2']
];
 
$io->table($headers, $rows);

样式向导的API接口是精悍的、有表现力的、直观的,为的是降低学习曲线:

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
$io = new SymfonyStyle($input, $output);
 
// common output elements 常规输出元素
$io->title(string $message);
$io->section(string $message);
$io->text(string|array $message);
$io->comment(string|array $message);
 
// more advanced output elements 高级输出元素
$io->note(string|array $message);
$io->caution(string|array $message);
$io->listing(array $elements);
$io->table(array $headers, array $rows);
 
// ask for user's input 要求用户输入
$io->ask(string $question, string|null $default = null, callable|null $validator = null);
$io->askHidden(string $question, callable|null $validator = null);
$io->confirm(string $question, bool $default = true);
$io->choice(string $question, array $choices, string|int|null $default = null);
 
// display the result of the command or some important task
// 显示当前命令或一些重要任务的执行结果
$io->success(string|array $message);
$io->error(string|array $message);
$io->warning(string|array $message);

在实践中,上述每一种元素在命令行中的实际显示效果如下:

使用全新的样式向导之主要优点在于:

  • 使你的命令在外观上保持一致,节省了你花在决定“哪个命令使用哪个样式”上的时间。

  • 精简了你的命令程序中的大量代码,剔除了数百行用于决定信息表现层的代码。

  • 你只需导入一个类(SymfonyStyle)即可替换掉诸多的类(TableProgressBarChoiceQuestionConfirmationQuestion等)。

本文在写作时,样式向导的文档还未准备好,但你可以查看内置于Symfony2.8或3.0中的源代码,它们是被整体重新设计的。