aura / cli
为命令行环境提供请求(Context)和响应(Stdio)类的等效功能,包括Getopt支持。
Requires
- php: >=7.2.0
Requires (Dev)
- aura/di: ~4.0
- phpunit/phpunit: ^8.5
README
为命令行界面提供请求(Context)和响应(Stdio)对象的等效功能,包括Getopt支持,以及一个独立的Help对象用于描述命令。
前言
安装
此库需要PHP 7.2或更高版本;我们原则上建议使用可用的最新PHP版本。
它没有用户空间依赖。
可以通过Composer以aura/cli的方式安装和自动加载。
或者,下载发布版或克隆此存储库,然后需要或包含其autoload.php文件。
质量
要在命令行运行单元测试,请发出composer install
,然后在包根目录下发出composer test
。这需要在命令行中作为composer
可用。
此库试图遵守PSR-1、PSR-2和PSR-4。如果您注意到遵守疏忽,请通过pull request发送补丁。
社区
要提问、提供反馈或与其他Aura社区进行交流,请加入我们的Google Group,关注@auraphp在Twitter上的动态,或者在Freenode上与我们聊天。
入门
上下文发现
Context对象提供有关命令行环境的信息,包括通过命令行传递的任何选项标志。(这是命令行与Web请求对象的等效。)
使用CliFactory实例化一个Context对象;传递一个$GLOBALS
的副本。
<?php use Aura\Cli\CliFactory; $cli_factory = new CliFactory; $context = $cli_factory->newContext($GLOBALS); ?>
您可以通过$env
、$server
和$argv
属性对象分别访问$_ENV
、$_SERVER
和$argv
值。(注意,这些属性是那些超全局变量在Context实例化时的副本。)如果相关的键缺失,您可以传递一个替代的默认值。
<?php // get copies of superglobals $env = $context->env->get(); $server = $context->server->get(); $argv = $context->argv->get(); // equivalent to: // $value = isset($_ENV['key']) ? $_ENV['key'] : null; $value = $context->env->get('key'); // equivalent to: // $value = isset($_ENV['key']) ? $_ENV['key'] : 'other_value'; $value = $context->env->get('key', 'other_value'); ?>
Getopt支持
Context对象提供了获取命令行选项和参数以及位置参数的支持。
要获取从命令行$argv
值解析的选项和参数,请使用Context对象的getopt()
方法。这将返回一个GetoptValues对象,您可以根据需要使用它。
定义选项和参数
要告诉getopt()
如何识别命令行选项,请传递一个选项定义数组。定义数组的格式类似于,但并非完全相同于PHP中的getopt()函数所使用的格式。不是在字符串中定义短标志和在单独的数组中定义长选项,而是将它们都定义为单个数组中的元素。在选项名称后添加一个*
表示它可以多次传递;其值将存储在数组中。
<?php $options = [ 'a', // short flag -a, parameter is not allowed 'b:', // short flag -b, parameter is required 'c::', // short flag -c, parameter is optional 'foo', // long option --foo, parameter is not allowed 'bar:', // long option --bar, parameter is required 'baz::', // long option --baz, parameter is optional 'g*::', // short flag -g, parameter is optional, multi-pass ]; $getopt = $context->getopt($options); ?>
注意:当我们在这里说“必需”时,意味着“当此选项存在时,它必须有一个参数。”这并不表示“此选项必须是存在的。”毕竟,这些都是选项。如果必须传递特定值,请考虑使用位置参数。
使用返回的 GetoptValues 对象上的 get()
方法检索选项值。您可以为缺少选项时提供备用默认值。
<?php $a = $getopt->get('-a', false); // true if -a was passed, false if not $b = $getopt->get('-b'); $c = $getopt->get('-c', 'default value'); $foo = $getopt->get('--foo', 0); // true if --foo was passed, false if not $bar = $getopt->get('--bar'); $baz = $getopt->get('--baz', 'default value'); $g = $getopt->get('-g', []); ?>
如果您想将一个选项名称别名为另一个名称,请用逗号分隔这两个名称。值将存储在两个名称下;
<?php // alias -f to --foo $options = [ 'foo,f:', // long option --foo or short flag -f, parameter required ]; $getopt = $context->getopt($options); $foo = $getopt->get('--foo'); // both -f and --foo have the same values $f = $getopt->get('-f'); // both -f and --foo have the same values ?>
如果您想允许一个选项被传递多次,请将一个 '*' 添加到选项名称的末尾。
<?php $options = [ 'f*', 'foo*:' ]; $getopt = $context->getopt($options); // if the script was invoked with: // php script.php --foo=foo --foo=bar --foo=baz -f -f -f $foo = $getopt->get('--foo'); // ['foo', 'bar', 'baz'] $f = $getopt->get('-f'); // [true, true, true] ?>
如果用户传递了不符合定义的选项,则 GetoptValues 对象会保留与解析失败相关的各种错误。在这种情况下,hasErrors()
将返回 true
,然后您可以查看错误。(错误实际上是 Aura\Cli\Exception
对象,但它们不会在发生时抛出;这样,您可以按需处理或忽略不同类型的错误。)
<?php $getopt = $context->getopt($options); if ($getopt->hasErrors()) { $errors = $getopt->getErrors(); foreach ($errors as $error) { // print error messages to stderr using a Stdio object $stdio->errln($error->getMessage()); } }; ?>
位置参数
要获取传递给命令行的位置参数,请使用 get()
方法和参数位置编号。
<?php $getopt = $context->getopt($options); // if the script was invoked with: // php script.php arg1 arg2 arg3 arg4 $val0 = $getopt->get(0); // script.php $val1 = $getopt->get(1); // arg1 $val2 = $getopt->get(2); // arg2 $val3 = $getopt->get(3); // arg3 $val4 = $getopt->get(4); // arg4 ?>
定义的选项将自动从参数中删除。
<?php $options = [ 'a', 'foo:', ]; $getopt = $context->getopt($options); // if the script was invoked with: // php script.php arg1 --foo=bar -a arg2 $arg0 = $getopt->get(0); // script.php $arg1 = $getopt->get(1); // arg1 $arg2 = $getopt->get(2); // arg2 $foo = $getopt->get('--foo'); // bar $a = $getopt->get('-a'); // 1 ?>
注意:如果短标志有一个可选参数,紧随其后的参数将被视为选项值,而不是参数。
标准输入/输出流
Stdio 对象允许您处理标准输入/输出流。(这是命令行与网络响应对象的等效物。)
使用 CliFactory 实例化一个 Stdio 对象。
<?php use Aura\Cli\CliFactory; $cli_factory = new CliFactory; $stdio = $cli_factory->newStdio(); ?>
默认情况下,使用 php://stdin
、php://stdout
和 php://stderr
,但您可以将任何流名称作为参数传递给 newStdio()
方法。
Stdio 对象的方法是 ...
-
getStdin()
、getStdout()
和getStderr()
返回相应的 Handle 对象; -
outln()
和out()
用于向 stdout 打印,带或不带换行符; -
errln()
和err()
用于向 stderr 打印,带或不带换行符; -
inln()
和in()
用于从 stdin 读取,直到用户按回车;inln()
留下尾随的换行符,而in()
则删除它。
您可以在输出和错误字符串中使用特殊格式化标记来设置文本颜色、文本粗细、背景颜色和其他显示特性。请参阅下面的格式化速查表。
<?php // print to stdout $stdio->outln('This is normal text.'); // print to stderr $stdio->errln('<<red>>This is an error in red.'); $stdio->errln('Output will stay red until a formatting change.<<reset>>'); ?>
退出代码
此库附带一个 Status 类,该类定义了退出状态代码的常量。您应尽可能使用这些常量。例如,如果命令使用了错误的参数数量或不正确的选项标志,请使用 exit()
与 Status::USAGE
。退出状态代码与在sysexits.h 中找到的相同。
编写命令
Aura.Cli 库不提供抽象或基类以从中扩展,但编写自己的命令是直接的。以下是一个独立的命令脚本,但类似的逻辑可以用于类中。将其保存为名为 hello
的文件,并用 php hello [-v,--verbose] [name]
调用它。
<?php use Aura\Cli\CliFactory; use Aura\Cli\Status; require '/path/to/Aura.Cli/autoload.php'; // get the context and stdio objects $cli_factory = new CliFactory; $context = $cli_factory->newContext($GLOBALS); $stdio = $cli_factory->newStdio(); // define options and named arguments through getopt $options = ['verbose,v']; $getopt = $context->getopt($options); // do we have a name to say hello to? $name = $getopt->get(1); if (! $name) { // print an error $stdio->errln("Please give a name to say hello to."); exit(Status::USAGE); } // say hello if ($getopt->get('--verbose')) { // verbose output $stdio->outln("Hello {$name}, it's nice to see you!"); } else { // plain output $stdio->outln("Hello {$name}!"); } // done! exit(Status::SUCCESS); ?>
编写命令帮助
有时为您的命令提供帮助输出将很有用。使用 Aura.Cli,Help 对象与您可能编写的任何命令都是分开的。它可以被外部操作或扩展。
例如,扩展 Help 对象并覆盖 init()
方法。
<?php use Aura\Cli\Help; class MyCommandHelp extends Help { protected function init() { $this->setSummary('A single-line summary.'); $this->setUsage('<arg1> [<arg2>]'); $this->setOptions([ 'f,foo' => "The -f/--foo option description.", 'bar::' => "The --bar option description.", ]); $this->setDescr("A multi-line description of the command."); } } ?>
然后实例化新类,并通过 Stdio 将其 getHelp()
输出传递。
<?php use Aura\Cli\CliFactory; use Aura\Cli\Context\OptionFactory; $cli_factory = new CliFactory; $stdio = $cli_factory->newStdio(); $help = new MyCommandHelp(new OptionFactory); $stdio->outln($help->getHelp('my-command')); ?>
我们将命令名称本身保留在帮助类之外,因为命令名称可能在不同项目中映射不同。
我们将一个GetoptParser传递给Help对象,以便它可以解析选项定义。
我们可以使用
getOptions()
从Help对象中获取选项定义;这允许我们将一个Help对象传递给一个假设的命令对象并重用这些定义。
输出将类似于以下内容
SUMMARY
my-command -- A single-line summary.
USAGE
my-command <arg1> [<arg2>]
DESCRIPTION
A multi-line description of the command.
OPTIONS
-f
--foo
The -f/--foo option description.
--bar[=<value>]
The --bar option description.
顺便提一下,传递给setOptions()
的选项数组可能还包含参数描述。它们的格式是#argname
(表示必需参数)和#argname?
(表示可选参数)。它们还可以用作键,对应描述值。在Getopt定义数组中忽略它们的 presence,但Help对象会读取它们并自动为它们生成输出。
例如,以下代码(注意缺少setUsage()
调用)...
<?php use Aura\Cli\CliFactory; use Aura\Cli\Context\OptionFactory; use Aura\Cli\Help; $cli_factory = new CliFactory; $stdio = $cli_factory->newStdio(); $help = new Help(new OptionFactory); $this->setSummary('A single-line summary.'); $help->setOptions([ 'f,foo' => "The -f/--foo option description.", 'bar::' => "The --bar option description.", '#arg1' => "The description for argument 1.", '#arg2?' => "The description for argument 2.", ]); $this->setDescr("A multi-line description of the command."); $stdio->outln($help->getHelp('my-command')); ?>
... 将生成以下输出
SUMMARY
my-command -- A single-line summary.
USAGE
my-command <arg1> [<arg2>]
DESCRIPTION
A multi-line description of the command.
ARGUMENTS
<foo>
The description for argument 1.
<bar>
The description for argument 2.
OPTIONS
-f
--foo
The -f/--foo option description.
--bar[=<value>]
The --bar option description.
格式化速查表
在POSIX终端上,<<markup>>
字符串将改变显示特性。请注意,这些不是HTML标签;它们将被转换为终端控制代码,并且不会被“关闭”。您可以在双尖括号之间放置尽可能多的空格分隔的标记代码。
reset reset display to defaults
black black text
red red text
green green text
yellow yellow text
blue blue text
magenta magenta (purple) text
cyan cyan (light blue) text
white white text
blackbg black background
redbg red background
greenbg green background
yellowbg yellow background
bluebg blue background
magentabg magenta (purple) background
cyanbg cyan (light blue) background
whitebg white background
bold bold in the current text and background colors
dim dim in the current text and background colors
ul underline in the current text and background colors
blink blinking in the current text and background colors
reverse reverse the current text and background colors
例如,要将加粗白色文本设置为红色背景,将<<bold white redbg>>
添加到您的输出或错误字符串中。使用<<reset>>
将其重置为正常。