在本系列文章的第二部分,我们介绍Symfony 3.2中针对Console Component的“DX/开发者体验改进(developer experience)”而新增的四个功能。
引入一个全新的Terminal类 ¶
命令行的Application
方法定义了几个方法,用于取得终端窗口的维度(高和宽):
1 2 3 4 5 6 | use Symfony\Component\Console\Application;
$application = new Application();
$dimensions = $application->getTerminalDimensions(); // [$width, $height] 宽高数组
$height = $application->getTerminalHeight();
$width = $application->getTerminalWidth(); |
从技术角度讲,要得到能够对应全部终端和操作系统的这个信息,会是一个复杂、缠绕、缓慢、易错的过程。在Symfony 3.2中我们决定把所有这些逻辑转移到一个全新的Terminal
类中:
1 2 3 4 | use Symfony\Component\Console\Terminal;
$height = (new Terminal())->getHeight();
$width = (new Terminal())->getWidth(); |
除此之外,我们还改进了获取/设置终端维度(Terminal Dimensions)的逻辑,以优先使用环境变量。如果COLUMN
和LINES
环境变量被定义,Terminal
使用它们的值来获取维度信息。当设置终端维度时,Termail
实例将创建或更新那些变量的值。
这个新的Terminal
类将被用于获取/设置除了维度之外的其他终端信息。目前,这些改进已经让我们修复了一些关于“当终端窗口过小时,进度条帮助方法(progress bar helper)所出现的极端情况”。
引入一个全新的StreamableInputInterface接口 ¶
在Symfony 2.8中我们引入了一个全新的Console命令行样式美化,简化了创建“外观一致”的命令的过程。但是,这些命令难于测试,特别是当使用ask()
帮助方法来请求用户的输入时。
在Symfony 3.2中,我们引入了全新的StreamableInputInterface
,并且让抽象类Symfony\Component\Console\Input\Input
实现该接口。这个改变,令得对“输入流(input stream)”的中心化管理,可以在一个单一的类中完成,同时令QuestionHelper
相关代码更加易于测试。
为ConsoleLogger添加了一个hasErrored()方法 ¶
Symfony 3.2中,ConsoleLogger
类包括了一个hasErrored()
方法,当一条ERROR
级别的信息被记录下来之后它立即返回true
。这样一来,你就不必再添加任何自定义逻辑,用于决定你的命令是否应该返回一个error exit code(exit(1)
,错误退出代码)。
添加了一个“Lockable(可锁定的)”trait ¶
在Symfony 2.6中我们引入了一个lock handler,用于提供一个简单的抽象层,借助文件锁(file lock)来锁定任何东西。这个lock handler(锁定控制器)主要用于避免并发问题以防止对同一命令的多次执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | use Symfony\Component\Filesystem\LockHandler;
class UpdateContentsCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$lock = new LockHandler('update:contents');
if (!$lock->lock()) {
// manage lock errors 管理锁定时出现的错误
}
// ...
}
} |
在Symfony 3.2中,得益于全新的LockableTrait
,我们把这个锁定控制器变得简单易用了些。这个trait提供了一个lock()
方法,用于创建一个在“当前命令之后”被命名的非防止锁定(non-blocking lock):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | use Symfony\Component\Console\Command\LockableTrait;
class UpdateContentsCommand extends Command
{
use LockableTrait;
protected function execute(InputInterface $input, OutputInterface $output)
{
if (!$this->lock()) {
// manage lock errors 管理锁定时出现的错误
}
// ...
}
} |
你也可以创建自定义名字的锁定,甚至能在“既有的锁定被释放之前”防止锁定。
1 2 3 4 5 | if (!$this->lock('custom_lock_name')) { ... }
// the second boolean argument tells whether the lock is blocking or not
// 第二个布尔值参数,指明是否需要防止锁定
if (!$this->lock('custom_lock_name', true)) { ... } |