如何在 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() 仍然像什么也没发生一样。
问题:
- getopt() 从哪里获取输入?
- 如何在 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
时,似乎 argc
和 argv
是直接从 Zend 引擎检索的,因此更改全局变量获胜'影响它的行为。您可以在此处查看 getopt
的源代码:https://github.com/php/php-src/blob/master/ext/standard/basic_functions.c#L4264.
无论如何,我几乎可以肯定你无法更改该输入。
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() 仍然像什么也没发生一样。
问题:
- getopt() 从哪里获取输入?
- 如何在 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
时,似乎 argc
和 argv
是直接从 Zend 引擎检索的,因此更改全局变量获胜'影响它的行为。您可以在此处查看 getopt
的源代码:https://github.com/php/php-src/blob/master/ext/standard/basic_functions.c#L4264.
无论如何,我几乎可以肯定你无法更改该输入。