OK, So PHP has a built-in getopt() function which returns information about what program options the user has provided. Only, unless I'm missing something, it's completely borked! From the manual:
The parsing of options will end at the first non-option found, anything that follows is discarded.
So getopt()
returns an array with the valid and parsed options only. You can still see the entire original command-line by looking at $argv
, which remains unmodified, but how do you tell where in that command-line getopt()
stopped parsing arguments? It is essential to know this if you want treat the remainder of a command-line as other stuff (like, e.g., file names).
Here's an example...
Suppose I want to set up a script to accept the following arguments:
Usage: test [OPTION]... [FILE]... Options: -a something -b something -c something
Then I might call getopt()
like this:
$args = getopt( 'abc' );
And, if I ran the script like this:
$ ./test.php -a -bccc file1 file2 file3
I should expect to have the following array returned to me:
Array ( [a] => [b] => [c] => Array ( [0] => [1] => [2] => ) )
So the question is this: How on Earth am I supposed to know that the three unparsed, non-option FILE
arguments start at $argv[ 3 ]
???
This behavior is a GNU extension, not available with libraries before glibc 2. By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end.
The getopt function returns the option character for the next command line option. When no more option arguments are available, it returns -1 .
getopt() function in C to parse command line arguments Return Value: The getopt() function returns different values: If the option takes a value, that value is pointer to the external variable optarg. '-1' if there are no more options to process.
An option character in this string can be followed by a colon (' : ') to indicate that it takes a required argument. If an option character is followed by two colons (' :: '), its argument is optional; this is a GNU extension. getopt has three ways to deal with options that follow non-options argv elements.
Starting with PHP 7.1, getopt
supports an optional by-ref param, &$optind
, that contains the index where argument parsing stopped. This is useful for mixing flags with positional arguments. E.g.:
user@host:~$ php -r '$i = 0; getopt("a:b:", [], $i); print_r(array_slice($argv, $i));' -- -a 1 -b 2 hello1 hello2 Array ( [0] => hello1 [1] => hello2 )
Nobody said you have ot use getopt. You may do it in any way you like:
$arg_a = null; // -a=YOUR_OPTION_A_VALUE $arg_b = null; // -b=YOUR_OPTION_A_VALUE $arg_c = null; // -c=YOUR_OPTION_A_VALUE $arg_file = null; // -file=YOUR_OPTION_FILE_VALUE foreach ( $argv as $arg ) { unset( $matches ); if ( preg_match( '/^-a=(.*)$/', $arg, $matches ) ) { $arg_a = $matches[1]; } else if ( preg_match( '/^-b=(.*)$/', $arg, $matches ) ) { $arg_b = $matches[1]; } else if ( preg_match( '/^-c=(.*)$/', $arg, $matches ) ) { $arg_c = $matches[1]; } else if ( preg_match( '/^-file=(.*)$/', $arg, $matches ) ) { $arg_file = $matches[1]; } else { // all the unrecognized stuff } }//foreach if ( $arg_a === null ) { /* missing a - do sth here */ } if ( $arg_b === null ) { /* missing b - do sth here */ } if ( $arg_c === null ) { /* missing c - do sth here */ } if ( $arg_file === null ) { /* missing file - do sth here */ } echo "a=[$arg_a]\n"; echo "b=[$arg_b]\n"; echo "c=[$arg_c]\n"; echo "file=[$arg_file]\n";
I always do it like that and it works. Moreover I can do whatever I want with it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With