如何在 getopt() 之前修改命令行参数

How to modify the command line arguments before getopt()

PHP 的 getopt() 不允许用 space 分隔参数及其可选值,需要用 '=' 分隔或不分隔:

# test.php uses getopt('a::')
> php test.php -a 3 // incorrect
> php test.php -a=3 // correct
> php test.php -a3 // correct

但另一方面,您可以使用 space 来分隔参数及其所需值(指定为 getopt('a:') )。为了使用 spaces 的一致性和直观性,我想在 getopt() 处理命令行之前更正命令行 - 我有一个正则表达式,用 '-abc= 替换 '-abc bc'公元前'.

但事实证明,修改$argv 对getopt() 没有影响。我用这个脚本做了一些测试:

# t.php
<?php
var_dump($argv);
$argv = array();
var_dump($argv);
var_dump(getopt('a'));
?>

> php t.php -a

array(2) {
  [0] =>
  string(5) "t.php"
  [1] =>
  string(2) "-a"
}
array(0) {
}
array(1) {
  'a' =>
  bool(false)
}

所以,$argv 是正确的,我已将它重写为空数组,但 getopt() 仍然像什么也没发生一样。

问题:

  1. getopt() 从哪里获取输入?
  2. 如何在 getopt() 解析之前修改此输入?

根据 Gustavo 的评论,我放弃了 getopt() 并创建了我自己的自定义解析器。它是更大的代码库的一部分,我无法在此处 post 因为它的代码太多了。我将 post 相关方法,我认为如果您需要这样的解决方案,您将能够填补空白:

public function parse()
{ 
    $i = 1;
    $max = count($GLOBALS['argv'])-1;
    while ($i <= $max) {
        // Disallow arguments like '---any', '--s' and '-long'
        $argName = $this->getArgumentName($GLOBALS['argv'][$i]);
        if ($argName !== false) {

            // Allow only previously defined arguments
            if (\array_key_exists($argName, $this->args)) {
                // Disallow arguments with empty values like '-s ""'
                if (($i < $max) && $GLOBALS['argv'][$i+1]=='') {
                    throw new SyntaxException("Empty values are not allowed", SyntaxException::BAD_SYNTAX);
                }
                // if argument without value then set it to true
                elseif ($i == $max || ($this->getArgumentName($GLOBALS['argv'][$i+1]) !== false)) {
                    $this->args[$argName]->setValue(true);
                    $i++;
                }
                // if argument with value then assign it the value
                else {
                    $this->args[$argName]->setValue($GLOBALS['argv'][$i+1]);
                    $i+=2;
                }
            } else throw new SyntaxException("Unexpected argument `$argName`", SyntaxException::UNEXPECTED_ARGUMENT);
        } else throw new SyntaxException("Wrong syntax of `{$GLOBALS['argv'][$i][0]}` argument", SyntaxException::BAD_SYNTAX);
    }

    return $this;
}

protected function getArgumentName($str)
{
    $name = \preg_replace('/(?:^-([\w\d])$)|(?:^--([\w\d][\w\d_?!.:-]+)$)/', '', $str,1);
    if (\is_null($name)) {
        throw new LogicException("Error in regexp with `$str` string");
    }
    return ($str == $name) ? false : $name;
}

关于差距:这些异常不是来自 SPL,它们是我自定义的异常层次结构。我这样做是为了让异常代码也成为脚本的 return 代码。 此外,$this->args 是一个 Argument 类型对象的集合,能够保存参数 type/behavior、名称、值、验证器等。

查看 PHP 源代码,当您调用 getopt 时,似乎 argcargv 是直接从 Zend 引擎检索的,因此更改全局变量获胜'影响它的行为。您可以在此处查看 getopt 的源代码:https://github.com/php/php-src/blob/master/ext/standard/basic_functions.c#L4264.

无论如何,我几乎可以肯定你无法更改该输入。