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 () — у меня есть регулярное выражение, которое заменяет ‘-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 () действовал так, как будто ничего не произошло.
Вопросы:
Глядя на исходный код PHP, кажется, что argc
а также argv
извлекаются непосредственно из движка Zend при вызове getopt
Таким образом, изменение глобалов не повлияет на его поведение. Вы можете проверить исходный код для getopt
Вот: https://github.com/php/php-src/blob/master/ext/standard/basic_functions.c#L4264.
Во всяком случае, я почти уверен, что вы не можете изменить этот ввод.
Следуя комментарию Густаво, я отказался от 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-> args — это коллекция объектов типа Argument, способных содержать тип / поведение аргумента, имя, значение, валидаторы и тому подобное.