spsostrov / getopt
SPŠ Ostrov GetOpt 库
Requires
- php: >=7.1
Requires (Dev)
- php: >=8.1
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.4
- squizlabs/php_codesniffer: ^3.7
README
这是一个PHP getopt库,具有以下设计目标:
- 干净的选项解析,与标准posix getopt库的兼容性非常接近。
- 简单的选项定义。每个选项类型都可以用一个字符串来定义。整个配置只是一个字符串数组。
- 支持选项检查、数组处理和其他酷炫功能。
用法
示例
use SPSOstrov\GetOpt\Options; $options = new Options([ 'r|regular-option This is a regular option', 'a|option-with-param: This is an option with an parameter', 'o|option-with-optional-param? This is an option with an optional parameter' ]); $args = ["-r", "-a", "argument", "-o"]; $parsed = $options->parseArgs($args);
选项定义
每个选项字符串由两个基本部分组成:选项定义和人类可读描述。选项定义不能包含空格(除非是引号内的),人类可读描述以第一个空格开头。
选项定义包含以下部分:
- 选项列表
- 可选类型指定
- 可选数量指定
- 可选写入规则
- 可选参数检查器
选项列表
每个选项都需要通过多个选项以 |
分隔来指定。例如:
o|option|simple-option
还有一些特殊选项名称:
@
- 表示所有未明确定义的短选项@@
- 表示所有未明确定义的长选项@@@
- 表示所有未明确定义的短选项和长选项- 如果列表以
$
开头,则选项将绑定到未命名的位置参数,而不是命名选项
处理未命名的位置参数
$command command
$args* command's positional arguments
这将把第一个未命名的位置参数存储到变量 command
中,并将所有其他变量存储到变量 args
中。
类型指定
有几个选项和参数类型。它们由一个字符后跟选项列表指定。类型字符可以是 ~
、?
、:
、*
。
option-without-param Option without parameter (may still hava a parameter, if quantity is specified)
option-without-param~ Option without parameter (explicitly set)
option-required-param: Option with required parameter
option-optional-param? Option with optional parameter
option-array-param* Option with multiple parameters
$argument Regular single argument
$optional-argument? Zero or one single argument
$array-argument* An array of arguments
$empty-argument~ Literally make no sense, but is available. Empty argument may be used if you want to explicitely disable positional arguments.
数量指定
数量指定单个选项可以出现多少次。它根据类型自动设置,但您可以显式设置它。
option{3} Exactly 3 options
option{1,5} From 1 to 5 options
option{4,} From 4 to infinity options
option{,5} From 0 to 5 options
option{,} From 0 to infinity options
请注意,数量和选项类型是完全独立的选项。另一方面,如果其中一项未指定,则从另一项计算得出。如果两项信息都未指定,首先将选项类型设置为 无参数,然后分配数量 {0,1}
。
默认数量
option~ Default quantity is {0,1}
option: Default quantity is {0,1}
option? Default quantity is {0,1}
option* Default quantity is {0,}
$arg~ Used for disabling positional arguments, makes no sense otherwise, default quantity is {0,0}
$arg: Default quantity is {1,1}
$arg? Default quantity is {0,1} (otherwise arg acts exactly the same as $arg:)
$arg* Default quantity is {0,}
默认类型根据以下规则从数量计算得出:
- 如果没有指定数量,选项默认为
~
。 - 如果没有指定数量,参数默认为
:
。 - 如果最大数量大于1(或无穷大),选项和参数默认为
*
。 - 所有其他情况默认为选项的
~
和参数的:
。
写入规则
选项和参数从命令行逐个接收。每个参数根据某些写入规则进行处理。每个写入都有一个可用的 变量注册表(即关联数组)。可以定义自定义操作。例如:
option:[opt] Write the value into the variable `opt` instead of variable `option`.
option:[option,op,x] Three custom rules. First write the value to variable `option` then write to `op` and last write to `x`
option[option="abc"] Write the string `abc` into variable `option` when --option is specified.
option[option=op] Write the value of the variable `op` into variable `option` when --option is specified.
option:[opt=$] Write the value of the option parameter into the variable `opt`. Same as `option[opt]`
o|option:[@=$] Write the value of the option parameter into all variables named as short options (i.e. write it into variable `o`).
o|option:[@@=$] Write the value of the option parameter into all variables named as long options (i.e. write it into variable `option`).
o|option:[@@@=$] Write the value of the option parameter into all variables (i.e. write it into `o` and `option). This is the default rule if no other is specified.
option[opt=@] Write the name of the really used option into the variable `opt`.
option[opt=@@] Same as above.
option[opt=@@@] Write the list of all options (separated by `|`) into the variable `opt`.
yes|no[enabled=@] Easy boolean implementation with possibility to keep default state.
yes|no{1}[enabled=@] Easy boolean implementation with possibility where explicitely setting one option is required.
low|medium|high{1}[speed=@] Easy tristate switch.
参数检查器
您还可以为每个选项指定参数检查器。当前版本尚未实现,但语法已经支持该功能。
option:=int # Check the option as `int`.
每个检查器都需要定义为字符串。但当前实现未指定如何将检查器分配给特定字符串。
禁用未命名的位置参数
默认情况下,即使在没有为它们提供选项定义的情况下,也允许未命名的位置参数。如果没有给出位置未命名的参数的规则,则使用默认规则。
$args*[__args__]
这意味着接受并存储任意数量的未命名位置参数到变量 __args__
中。如果您想禁用此默认行为,只需添加一个带有 空参数 的规则即可。例如
$args~
这将导致默认规则消失,并且不会使用其他未命名的位置参数。一方面,空参数 规则可以与其他未命名的位置参数规则结合使用,但另一方面则没有意义。没有理由将 空参数 与其他类型的参数结合,因为 空参数 实际上什么也不做。因此,空参数 的唯一用途是禁用接受未命名位置参数的默认行为,即使没有定义。
提供帮助
在任意空白字符之后,出现帮助信息的描述符。通常,只需在这里传递一个帮助描述即可。例如
c|cool-option: This is a very cool option
但在某些情况下,可能需要一个更可调的方法。您可以将选项从组中拆分到更小的组中。例如
o|c|option|cool-option [o|option] This option is not cool.[c|cool-option] This option is very cool.
这意味着四个选项的组 o
、c
、option
、cool-option
(例如,由于数量计算,它们可以合并为一个组)将拆分为两个 "子组"
- 仅包含
o
和option
的组,其描述为此选项并不酷。
- 仅包含
c
和cool-option
的组,其描述为此选项非常酷。
拆分到子组仅用于生成帮助。否则,所有选项都作为单个组处理。
可以使用通配符选项
s|S|long-option|long [@] Short options. [@@] Long options.
这将创建两个 "帮助" 组
- 包含
s
和S
的组,其描述为简短选项。
- 包含
long-option
和long
的组,其描述为长选项。
如果选项有参数,您还可以指定选项的参数名称。例如
parametric-option: [=param] Parametric option.
这将导致渲染此选项的帮助信息为
--parametric-option=<param> Parametric option.
指定参数名称和分组可以组合使用
by-id|by-name:{1} [by-id=id] Select entity by id. [by-name=name] Select entity by name.
这将渲染
--by-id=<id> Select entity by id.
--by-name=<name> Select entity by name.
每个字符串中多个选项
在某个字符串中指定多个选项也是可能的。在这种情况下,使用换行符来分隔选项。如果帮助文本的每一行都以空格开头,也可以将帮助文本拆分为多行
$options = <<<'EOPT'
h|help Print help
l|long-option
This option has a long help
so the help text may be splitted into
multiple lines.
EOPT;
调整选项对象。
创建 SPSOstrov\GetOpt\Options
类的实例后,您可以调整一些设置
use SPSOstrov\GetOpt\Options; $options = new Options($optionDefinitionList); // additionally register other option. If registered in non-strict mode, // it is allowed to share option names with existing options. In such a case // such a name will be just ignored. $options->registerOption($optionDefinition, $strict); // set the argv[0] argument (i.e. command name). This is used when generating help. // if no argv[0] argument is set, the really used command name is used or it is just // set to `"command"` not invoked from CLI. $options->setArgv0("some-command"); // Enable or disable the strict mode of option parsing. The difference in both modes // (strict and non-strict) is what happens if some invalid option name is recognized. // In strict mode an exception is thrown in non-strict mode invalid option is recognized // as the first positional unnamed argument. // Default mode is strict. $options->setStrictMode(false); // Enable or disable the GNU mode of option parsing. When GNU mode enabled, // first non-option argument will not end up option parsing and an explicit `--` is // required to force all other arguments being understood as arguments (non-options) // Default mode is non-gnu. $options->setGnuMode(true); // Tune how the option with an optional parameter will be parsed. Lets assume we have // such option with optional argument -o. And the command arguments are "-o optional". // If standalone optional arguments are allowed, this will be understood as option // "-o" having the argument "optional". // If standalone optional arguments are not allowed, this will be understood as option // "-o" without any parameter succeeded by a positional unnamed argument with value // "optional". $option->setStandaloneOptionalArgAllowed(true);
生成帮助
直接格式化帮助
use SPSOstrov\GetOpt\Options; $options = new Options($optionDefinitionList); // Easiest way: echo $options->getHelpFormatted(); // Print just help for options: echo $options->getOptionsHelpFormatted(); // Print just help for positional unnamed arguments: echo $options->getArgsHelpFormatted();
获取对生成帮助有用的结构化数据
如果您想自己构建帮助,也提供了该用途的结构化数据
use SPSOstrov\GetOpt\Options; $options = new Options($optionDefinitionList); // Get list of options. The result is an array of associative arrays, each containing these keys: // * short - array of short options // * long - array of long options // * argName - name of the argument (parameter) of the option if the option has one. May be null // even if the option has an argument (parameter). In such a case a default like "arg" // should be picked // * argType - type of the argument (see constants ARG_* in Options class) // * description - the description of the options $optionsHelp = $options->getOptionsHelp(); // Get list of positional unnamed arguments. The result is an array of associative arrays, each // containing these keys: // * argName - name of the argument // * argType - type of the argument (see constants ARG_* in Options class) // * description - the description of the argument $argsHelp = $options->getArgsHelp();
使用自定义格式化程序格式化帮助
如果您想使用自己的帮助格式,可以基于 getOptionsHelp()
/getArgsHelp()
方法构建自己的帮助渲染器,或者创建一个自定义渲染器,然后可以将其用于 GetOpt 的核心。您只需实现具有以下方法的 SPSOstrov\GetOpt\FormatterInterface
接口
// Formats the whole option list as a single string. // (return null, if the option list is considered as empty) public function formatOptionsHelp(array $options): ?string; // Formats the whole argument list as a single string. // (return null, if the argument list is considered as empty) public function formatArgsHelp(array $args): ?string; // Format the whole help, where the results from formatOptionsHelp() and // formatArgsHelp() are available. Also the $argv0 parameter is available. // It is expected to be always a string result. public function formatHelp(string $argv0, ?string $args, ?string $options): string;
一旦您实现了此接口并有一个此类格式化程序的实例,您可以使用两种方式使用它
- 通过调用
SPSOstrov\GetOpt\Formatter::setDefault($formatter);
使其成为系统默认格式化程序 - 将其传递给帮助生成方法,例如:
$help = $options->getHelpFormatted($formatter);
其他功能
表格格式化
有一个通用的表格格式化功能可用于 ASCII 输出。您也可以在自己的应用程序中使用它,因为它解决了将文本格式化为列的困难部分。只有部分实现的表格 API 已有文档。 请仅使用已记录的函数,因为未记录的函数仍应被视为不稳定。
用法示例
use SPSOstrov\GetOpt\AsciiTable; // Setup a table with output encoding utf8, width of 120 chars and two columns. // First column has left and right padding set to 1 space // second column has left padding 0 zpaces and right padding set to 1 space // Don't use any other arguments of the column, they are considered as unstable. $table = (new AsciiTable())->encoding("utf8")->width(120)->column(1)->column([0, 1]); $data = [ ["--option", "This option is not cool."], ["--cool-option", "This is a very cool option"], ]; $output = $table->render($data); echo $output;
块格式化程序
如果没有指定其他格式化器,则默认格式化器(类 SPSOstrov\GetOpt\DefaultFormatter
)将被用作默认。此格式化器使用多个块。如果您想将自定义块添加到帮助文档中,可以使用默认格式化器的功能。您需要获取格式化器的实例。
有两种方法可以实现
use SPSOstrov\GetOpt\Formatter; use SPSOstrov\GetOpt\DefaultFormatter; // 1st way: // Get the default instance. If nothing is set it defaults to an instance of DefaultFormatter. $instance = Formatter::instance() // 2nd way: // Create a completely new formatter: $instance = new DefaultFormatter();
此默认格式化器有一些特殊方法
$formatter->setWidth(150)
- 设置格式化器使用的宽度。$formatter->getWidth($indent)
- 获取整个块的宽度(当 $indent 为 false 时)或子块的宽度(当 $indent 为 true 时)$formatter->formatBlock($blockCaption, $blockText)
- 输出具有给定标题的块的格式。如果 $blockText 为 null,则整个块不会被渲染。如果$blockCaption
为 null,则只渲染标题。$blockText 将缩进。
创建带有换行文本的块
如果您想创建具有常规换行的良好缩进的文本,则需要结合使用 AsciiTable 和默认格式化器
use SPSOstrov\GetOpt\AsciiTable; use SPSOstrov\GetOpt\Formatter; function formatDescription(?string $description): string { // We rely on the fact that the system-wide default formatter is an instance of DefaultFormatter: $formatter = Formatter::instance(); if ($description !== null) { $table = (new AsciiTable())->encoding('utf8')->width($formatter->getWidth(true))->column(); return $ormatter->formatBlock("Description:", $table->render([[$description]])); } else { return ''; } }