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

时间:2015-10-01 22:19:05

标签: php command-line-interface getopt

PHP的getopt()不允许将参数及其可选值与空格分开,需要用' ='分隔。或不分开:

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

但另一方面,你可以使用空格来分隔参数及其所需的值(一个指定为getopt(' a:'))。为了使用空格的一致性和直观性,我想在getopt()处理之前纠正命令行 - 我有一个正则表达式替换了#ab; -abc bc'与' -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()解析之前修改此输入?

2 个答案:

答案 0 :(得分:1)

查看PHP源代码,当您调用(defun sum-rec (n) (if (not (eq n 0)) (+ (sum-rec(- n 1)) n) 0)) > (format t "ans = ~A~%" (sum-rec 4)) ans = 10 时,似乎直接从Zend引擎检索argcargv,因此更改全局变量不会影响其行为。您可以在此处查看getopt的源代码:https://github.com/php/php-src/blob/master/ext/standard/basic_functions.c#L4264

无论如何,我几乎可以肯定你无法改变这种意见。

答案 1 :(得分:0)

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

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_?!.:-]+)$)/', '$1$2', $str,1);
    if (\is_null($name)) {
        throw new LogicException("Error in regexp with `$str` string");
    }
    return ($str == $name) ? false : $name;
}

关于差距:这些异常不是来自SPL,它们是我的自定义异常层次结构。我这样做,以便异常代码也是脚本'返回代码。 此外,$ this-&gt; args是Argument类型对象的集合,能够保存参数类型/行为,名称,值,验证器等。