Aura.Cli



简介

Aura CLI包提供了一个创建和执行CLI Command命令行对象的系统。它包含解析命令行参数和处理标准输入输出流的组件,而且也是基于信号的。

Aura CLI包依赖aura.diaura.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框架,它会帮你处理所有工作,但如果你不想使用整个框架,那么你不得不自己写这些代码。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>