spsostrov/getopt

SPŠ Ostrov GetOpt 库

v0.3.0 2024-02-09 01:44 UTC

This package is auto-updated.

Last update: 2024-09-09 02:59:26 UTC


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.

这意味着四个选项的组 ocoptioncool-option(例如,由于数量计算,它们可以合并为一个组)将拆分为两个 "子组"

  1. 仅包含 ooption 的组,其描述为 此选项并不酷。
  2. 仅包含 ccool-option 的组,其描述为 此选项非常酷。

拆分到子组仅用于生成帮助。否则,所有选项都作为单个组处理。

可以使用通配符选项

s|S|long-option|long [@] Short options. [@@] Long options.

这将创建两个 "帮助" 组

  1. 包含 sS 的组,其描述为 简短选项。
  2. 包含 long-optionlong 的组,其描述为 长选项。

如果选项有参数,您还可以指定选项的参数名称。例如

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;

一旦您实现了此接口并有一个此类格式化程序的实例,您可以使用两种方式使用它

  1. 通过调用 SPSOstrov\GetOpt\Formatter::setDefault($formatter); 使其成为系统默认格式化程序
  2. 将其传递给帮助生成方法,例如: $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();

此默认格式化器有一些特殊方法

  1. $formatter->setWidth(150) - 设置格式化器使用的宽度。
  2. $formatter->getWidth($indent) - 获取整个块的宽度(当 $indent 为 false 时)或子块的宽度(当 $indent 为 true 时)
  3. $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 '';
    }
}