getopt
(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
getopt — コマンドライン引数のリストからオプションを取得する
説明
スクリプトに渡されたオプションをパースします。
パラメータ
short_options
-
この文字列の各文字をオプション文字として使用し、
スクリプトにハイフンひとつ (
-
) で始まるオプションとして渡された内容とマッチさせます。 たとえば、オプション文字列"x"
は-x
というオプションを認識します。 a-z、A-Z および 0-9 のみを認識します。 long_options
-
オプションの配列。
この配列の各要素をオプション文字列として使用し、
スクリプトにハイフンふたつ (
--
) で始まるオプションとして渡された内容とマッチさせます。 たとえば、longopts の要素"opt"
は--opt
というオプションを認識します。 rest_index
-
rest_index
パラメータが与えられると、 引数のパースを止めた時点のインデックスがこの変数に書き込まれます。
short_options
パラメータに含まれる要素には次のようなものがあります。
- 単一の文字 (値を受け付けない)
- 文字の後にコロンをひとつ続けたもの (値が必須であるパラメータ)
- 文字の後にコロンをふたつ続けたもの (値がオプションであるパラメータ)
注意: オプションの値で、
" "
(空白) を区切り文字として使用することはできません。
long_options
パラメータに含まれる要素には次のようなものがあります。
- 文字列 (値を受け付けない)
- 文字列の後にコロンをひとつ続けたもの (値が必須であるパラメータ)
- 文字列の後にコロンをふたつ続けたもの (値がオプションであるパラメータ)
注意:
short_options
とlong_options
の書式はほぼ同じです。唯一の違いは、long_options
はオプションの配列 (その各要素がオプションとなる) を受け取るけれどもshort_options
は文字列 (その各文字がオプションとなる) を受け取るということです。
戻り値
この関数はオプション/引数のペアを連想配列で返します。
失敗した場合に false
を返します。
注意:
オプション以外のものが見つかった時点でオプションのパースは終了し、 それ以降の内容は破棄されます。
変更履歴
バージョン | 説明 |
---|---|
7.1.0 |
rest_index パラメータが追加されました。
|
例
例1 getopt() の例:基本編
<?php
// スクリプト example.php
$options = getopt("f:hp:");
var_dump($options);
?>
shell> php example.php -fvalue -h
上の例の出力は以下となります。
array(2) { ["f"]=> string(5) "value" ["h"]=> bool(false) }
例2 getopt() の例:長いオプション
<?php
// スクリプト example.php
$shortopts = "";
$shortopts .= "f:"; // 値が必須
$shortopts .= "v::"; // 値がオプション
$shortopts .= "abc"; // これらのオプションは値を受け取りません
$longopts = array(
"required:", // 値が必須
"optional::", // 値がオプション
"option", // 値なし
"opt", // 値なし
);
$options = getopt($shortopts, $longopts);
var_dump($options);
?>
shell> php example.php -f "value for f" -v -a --required value --optional="optional value" --option
上の例の出力は以下となります。
array(6) { ["f"]=> string(11) "value for f" ["v"]=> bool(false) ["a"]=> bool(false) ["required"]=> string(5) "value" ["optional"]=> string(14) "optional value" ["option"]=> bool(false) }
例3 getopt() の例:複数のオプションを一度に渡す
<?php
// スクリプト example.php
$options = getopt("abc");
var_dump($options);
?>
shell> php example.php -aaac
上の例の出力は以下となります。
array(2) { ["a"]=> array(3) { [0]=> bool(false) [1]=> bool(false) [2]=> bool(false) } ["c"]=> bool(false) }
例4 getopt() の例: rest_index
を使う
<?php
// Script example.php
$rest_index = null;
$opts = getopt('a:b:', [], $rest_index);
$pos_args = array_slice($argv, $rest_index);
var_dump($pos_args);
shell> php example.php -a 1 -b 2 -- test
上の例の出力は以下となります。
array(1) { [0]=> string(4) "test" }
User Contributed Notes 26 notes
Be sure to wrap your head around this PHP jewel that took me a while to comprehend:
The returned array will contain a boolean FALSE for options that HAVE been specified.
Because why use TRUE to indicate "yes, it's there" when you can also use FALSE for that purpose, right? This is completely counter-intuitive and is most certainly only ever possible in PHP-land.
Sometimes you will want to run a script from both the command line and as a web page, for example to debug with better output or a command line version that writes an image to the system but a web version that prints the image in the browser. You can use this function to get the same options whether passed as command line arguments or as $_REQUEST values.
<?php
/**
* Get options from the command line or web request
*
* @param string $options
* @param array $longopts
* @return array
*/
function getoptreq ($options, $longopts)
{
if (PHP_SAPI === 'cli' || empty($_SERVER['REMOTE_ADDR'])) // command line
{
return getopt($options, $longopts);
}
else if (isset($_REQUEST)) // web script
{
$found = array();
$shortopts = preg_split('@([a-z0-9][:]{0,2})@i', $options, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$opts = array_merge($shortopts, $longopts);
foreach ($opts as $opt)
{
if (substr($opt, -2) === '::') // optional
{
$key = substr($opt, 0, -2);
if (isset($_REQUEST[$key]) && !empty($_REQUEST[$key]))
$found[$key] = $_REQUEST[$key];
else if (isset($_REQUEST[$key]))
$found[$key] = false;
}
else if (substr($opt, -1) === ':') // required value
{
$key = substr($opt, 0, -1);
if (isset($_REQUEST[$key]) && !empty($_REQUEST[$key]))
$found[$key] = $_REQUEST[$key];
}
else if (ctype_alnum($opt)) // no value
{
if (isset($_REQUEST[$opt]))
$found[$opt] = false;
}
}
return $found;
}
return false;
}
?>
Example
<?php
// php script.php -a -c=XXX -e=YYY -f --two --four=ZZZ --five=5
// script.php?a&c=XXX&e=YYY&f&two&four=ZZZ&five=5
$opts = getoptreq('abc:d:e::f::', array('one', 'two', 'three:', 'four:', 'five::'));
var_dump($opts);
/**
array(7) {
'a' => bool(false)
'c' => string(3) "XXX"
'e' => string(3) "YYY"
'f' => bool(false)
'two' => bool(false)
'four' => string(3) "ZZZ"
'five' => string(1) "5"
}
*/
?>
"phpnotes at kipu dot co dot uk" and "tim at digicol dot de" are both wrong or misleading. Sean was correct. Quoted space-containing strings on the command line are one argument. It has to do with how the shell handles the command line, more than PHP. PHP's getopt() is modeled on and probably built upon the Unix/POSIX/C library getopt(3) which treats strings as strings, and does not break them apart on white space.
Here's proof:
$ cat opt.php
#! /usr/local/bin/php
<?php
$options = getopt("f:");
print_r($options);
?>
$ opt.php -f a b c
Array
(
[f] => a
)
$ opt.php -f 'a b c'
Array
(
[f] => a b c
)
$ opt.php -f "a b c"
Array
(
[f] => a b c
)
$ opt.php -f a\ b\ c
Array
(
[f] => a b c
)
$
Beware, this function can be dangerous for options following arguments when, for example, you make use of a --dry-run option, due to this behaviour:
"Note: The parsing of options will end at the first non-option found, anything that follows is discarded."
My script was doing a live run even though I specified --dry-run as the last part of the command like this `php foo.php arg1 --dry-run`: getopt() did NOT include dry-run in its list of options resulting in my script executing a live run.
getopt() only returns the options specified if they were listed in the options.
So you cant make a switch() use default: to complain of an unknown option. :(
To elaborate on what 'ch1902' said, there certainly are instances where you may need to execute a script via CLI and the HTTP protocol. In such an instance, you can normalize how your script parses via CLI (using getopt()) as well as via HTTP (using $_GET) with the following simplified code:
<?php
// PHP 5.4+ only due to the new array brace style.
function request(array $options = []) {
// Set the default values.
$defaults = [
'params' => '',
'os' => '',
'username' => posix_getpwuid(posix_geteuid())['name'],
'env' => ''
];
$options += $defaults;
// Sufficient enough check for CLI.
if ('cli' === PHP_SAPI) {
return getopt('', ['params:', 'os::', 'username::', 'env::']) + $options;
}
return $_GET + $options;
}
print_r(request());
?>
The above code would yield the results below when access via CLI and HTTP.
/**
* params = foo/bar
* username = housni.yakoob
*/
// CLI
$ php script.php --params=foo/bar --username=housni.yakoob
Array
(
[params] => foo/bar
[username] => housni.yakoob
[os] =>
[env] =>
)
// HTTP
script.php?params=foo/bar&username=housni.yakoob
Array
(
[params] => foo/bar
[username] => housni.yakoob
[os] =>
[env] =>
)
/**
* params = foo/bar
* username = Not provided, therefore, the default value will be used.
*/
// CLI
$ whoami && php script.php --params=foo/bar
housni // <-- Current users usersname (output of `whoami`).
Array
(
[params] => foo/bar
[os] =>
[username] => housni
[env] =>
)
// HTTP
script.php?params=foo/bar
Array
(
[params] => foo/bar
[os] =>
// The username of my Apache user, the result of posix_getpwuid(posix_geteuid())['name']
[username] => www-data
[env] =>
)
As you can see, the output is consistent when the script is executed via the CLI or the web.
One thing of important note would be that getopt() actually respects the '--' option to end an option list. Thus given the code:
test.php:
<?php
$options = getopt("m:g:h:");
if (!is_array($options) ) {
print "There was a problem reading in the options.\n\n";
exit(1);
}
$errors = array();
print_r($options);
?>
And running:
# ./test.php ./run_vfs -h test1 -g test2 -m test3 -- this is a test -m green
Will return:
Array
(
[h] => test1
[g] => test2
[m] => test3
)
Whereas running:
# /test.php ./run_vfs -h test1 -g test2 -m test3 this is a test -m green
Will return:
Array
(
[h] => test1
[g] => test2
[m] => Array
(
[0] => test3
[1] => green
)
)
After getopt() of PHP5.3.0 (on Windows) ignored some parameters if there was a syntactical problem, I decided to code my own generic parameter parser.
<?php
/**
* Parses $GLOBALS['argv'] for parameters and assigns them to an array.
*
* Supports:
* -e
* -e <value>
* --long-param
* --long-param=<value>
* --long-param <value>
* <value>
*
* @param array $noopt List of parameters without values
*/
function parseParameters($noopt = array()) {
$result = array();
$params = $GLOBALS['argv'];
// could use getopt() here (since PHP 5.3.0), but it doesn't work relyingly
reset($params);
while (list($tmp, $p) = each($params)) {
if ($p{0} == '-') {
$pname = substr($p, 1);
$value = true;
if ($pname{0} == '-') {
// long-opt (--<param>)
$pname = substr($pname, 1);
if (strpos($p, '=') !== false) {
// value specified inline (--<param>=<value>)
list($pname, $value) = explode('=', substr($p, 2), 2);
}
}
// check if next parameter is a descriptor or a value
$nextparm = current($params);
if (!in_array($pname, $noopt) && $value === true && $nextparm !== false && $nextparm{0} != '-') list($tmp, $value) = each($params);
$result[$pname] = $value;
} else {
// param doesn't belong to any option
$result[] = $p;
}
}
return $result;
}
?>
A call like: php.exe -f test.php -- alfons -a 1 -b2 -c --d 2 --e=3=4 --f "alber t" hans wurst
and an in-program call parseParameters(array('f')); would yield in a resulting array:
Array
(
[0] => alfons
[a] => 1
[b2] => 1
[c] => 1
[d] => 2
[e] => 3=4
[f] => 1
[1] => alber t
[2] => hans
[3] => wurst
)
As you can see, values without an identifier are stored with numeric indexes. Existing identifiers without values get "true".
Unfortunately, even using Example #4 do not allow to easily detect a bad -x or --xx argument as the last -x or --xx is always “eaten” even if it is bad:
If I use this (Example #4) :
<?php
// Script example.php
$rest_index = null;
$opts = getopt('a:b:', [], $rest_index);
$pos_args = array_slice($argv, $rest_index);
var_dump($pos_args);
?>
shell> php example.php -a 1 -b 2
shell> php example.php -a 1 -b 2 --test
shell> php example.php -a 1 -tb 2
All return the same result (-t and --test not defined) :
array(0) {
}
(last one use combining single letters, making user testing much much more complicated)