简介
Aura CLI包提供了一个创建和执行CLI Command命令行对象的系统。它包含解析命令行参数和处理标准输入输出流的组件,而且也是基于信号的。
Aura CLI包依赖aura.di和aura.signal包。
基本用法
动作和输入/输出
命令Command的逻辑处理一般在action()方法中。在下面的示例中,我们将演示基本的输入/输出。
<?php
namespace vendor\package;
use aura\cli\Command;
class Example extends Command
{
public function action()
{
$this->stdio->outln('Hello World!');
$this->stdio->out('Please enter some text: ');
$input = $this->stdio->in();
$this->stdio->errln('Input was ' . $input);
}
}
当调用这个命令Command时,将会输出"Hello Wordl!",询问用户输入,最后输出用户输入或错误流。
使用$stdio对象处理标准输入/输出流。该对象具有以下方法:
outln() 和 out():写入到标准输出流,第一个方法输出的结尾有换行符,第二个则没有。
errln() 和 err():写入到标准错误流,第一个方法输出的结尾有换行符,第二个则没有。
inln() 和 in():从标准输入流读入,直到用户敲回车键。第一个方法将保留输入末尾的换行符,第二个则不会。
信号钩子
Aura的CLI 命令Command有四个信号钩子;这些钩子是通过信号管理器$signal调用的。在动作前后使用pre-和post-action方法,在命令启动和退出前后使用pre-和post-exec方法。
<?php
namespace vendor\package;
use aura\cli\Command;
class Example extends Command
{
protected $input = 'foo bar baz';
public function preExec()
{
// perform object setup here
}
public function preAction()
{
$this->stdio->outln('The input is currently ' . $this->input);
}
public function action()
{
$this->stdio->out('Please enter some text: ');
$this->input = $this->stdio->in();
}
public function postAction()
{
$this->stdio->outln('The input was ' . $this->input);
}
public function postExec()
{
// perform object teardown here
}
}
变量参数
传递命令行参数也是命令调用的一部分。在Command对象中获取命令行参数,要使用$this->params属性。
<?php
namespace vendor\package;
use aura\cli\Command;
class Example extends Command
{
public function action()
{
foreach ($this->params as $key => $val) {
$this->stdio->outln("Param $key is '$val'.");
}
}
}
例如,如果我们输入命令。。。
$ php command.php foo bar baz
。。。那么action()方法将会输出:
Param 0 is 'foo'.
Param 1 is 'bar'.
Param 2 is 'baz'.
高级用法
长短选项
除了变量参数,我们还希望在调用命令的时候能够传入某些短开关和长选项参数。一般在命令行中以-a和--option=value形式出现。
为了处理选项,首先在Command对象中定义$options数组。然后就可以使用$getopt方法获取各选项值。
下面来看看关于命令行选项的示例:
<?php
namespace vendor\package;
use aura\cli\Command;
use aura\cli\Option;
class Example extends Command
{
protected $options = array(
'foo_bar' => array(
'long' => 'foo-bar',
'short' => 'f',
'param' => Option::PARAM_REQUIRED,
'multi' => false,
'default' => null,
),
);
public function action()
{
$this->stdio->out("The value of -f/--foo-bar is ")
$this->stdio->outln($this->getopt->foo_bar);
}
}
当我们调用上面命令时。。。
$ php command.php --foo-bar=gir
。。。它会输出:
The value of -f/--foo-bar is gir.
$options数组的键名就是选项的名称,而每个元素又是一个选项定义数组,键名如下:
'long': 长格式选项,在命令行中以两个"-"符号开始。长格式的参数值是等号后面的值;例如:--foo-bar=some_value。如果不需要长格式选项,此值留空即可。
'short': 短格式选项,在命令行中以一个"-"符号开始。短格式的参数值是空格后面的值;例如:-f some_value。如果不需要短格式选项,此值留空即可。
'param': 选项值是必须的,还是可选的,又或者是不允许的?Option::PARAM_REQUIRED表示必须传递参数值,Option::PARAM_OPTIONAL表示参数值是可选的,Option::PARAM_REJECTED表示不允许传入任何参数值。
'multi': 选项是否允许在同一个命令中多递传递?例如:传入"-f foo -f bar -f zim"将会传入一个数组选项值(数组元素:'foo', 'bar', 'zim')。
'default': 未传递参数时的默认值。
定义好选项并在命令行中传值后,我们可以使用$getopt对象获取选项值,就好像魔述获取类属性一样。因此,对于上面的'foo_bar'选项,我们使用$this->getopt->foo_bar获取它的值。
信号和取消动作
在执行exec()期间,Command会发送一个'pre_exec'信号给信号管理器,并把命令Command对象作为唯一参数传递给信号管理器。根据需要在这里设置命令Command对象。
在action()方法执行之前,命令Command对象会发送一个'pre_action'信号给信号管理器,并把命令Command对象作为唯一参数传递给信号管理器。
要中止action()方法运行,只需在'pre_action'信号处理器中调用命令Command对象的skipAction()方法即可。这将会跳过action()方法,直接执行'post_exec'信号。
action()方法执行完后,命令Command对象会发送一个'post_action'信号给信号管理器,并把命令Command对象作为唯一参数传递给信号管理器。(如果跳过了action()方法,'post_action'信号也不会被发送。)
最后,在exec()方法结束之前,命令Command对象会发送一个'post_exec'信号给信号管理骂,并把命令Command对象作为唯一参数传递给信号管理器。在命令执行完毕后,根据需要执行清理工作。
调用脚本和命令工厂
在我们执行命令Command对象前,我们需要一个“调用脚本”。它相当于CLI环境下的引导脚本。调用脚本是我们在命令行执行的文件;它建立执行环境,创建命令Command对象并且执行它。
在调用脚本中,不要直接实例化命令Command类。而应该创建一个数组映射(短命令名称=>关联类名称),并使用CommandFactory创建该短命令名称的命令Command对象。
例如,下面的代码将会实例化vendor.package/src目录下的vendor\package\Example类并执行它。代码有些长,且为了实现必要的功能,使用了Aura的其它包。
<?php
// create a map of command names to command classes
$command_map = array(
'example' => 'vendor\package\Example',
);
// set up an autoloader
$loader = require '/path/to/aura.autoload/scripts/instance.php';
$loader->register();
$loader->addPrefix('aura\di\\', '/path/to/aura.di/src');
$loader->addPrefix('aura\signal\\', '/path/to/aura.signal/src');
$loader->addPrefix('aura\cli\\', '/path/to/aura.cli/src');
$loader->addPrefix('vendor\package\\', '/path/to/vendor.package/src');
// instantiate and configure the DI container.
use aura\di\Container;
use aura\di\Forge;
use aura\di\Config;
$di = new Container(new Forge(new Config));
require '/path/to/aura.signal/config/default.php';
require '/path/to/aura.cli/config/default.php';
// get the cli context object from the DI container, then discard the
// invoking script name from the cli context argument values
$context = $di->get('cli_context');
$context->shiftArgv();
// get the command factory from the DI container and add the command map
$factory = $di->get('cli_command_factory');
foreach ($command_map as $name => $class) {
$factory->map($name, $class);
}
// using first cli context argument as the short command name,
// get a new command object instance and then execute it.
try {
$command = $factory->newInstance($context->shiftArgv());
$command->exec();
} catch (Exception $e) {
echo $e->getMessage() . PHP_EOL;
}
把上述代码存到command.php文件中。然后在命令行中键入php /path/to/command.php example命令,它将会执行vendor\package\Example类。
哇哦,你可以觉得代码太多了。如果你使用aura.system框架,它会帮你处理所有工作,但如果你不想使用整个框架,那么你不得不自己写这些代码。
Recent Comments