I am writing a small command line application in php.
What is the correct way to handle command line arguments and options?
There seems to be the argv array, $_SERVER['argv'], and getopt but its confusing when to use each?
Also with regards to options i.e. "argument --option" what is the best way to get these?
One day I decided to defeat this monster once and for all. I forged a secret weapon - a function that acts as a storage, a parser and a query function for arguments.
// You can initialize it with a multiline string:
arg("
-a --alpha bool Some explanation about this option
-b --beta bool Beta has some notes too
-n --number int Some number you need for the script
- --douglas int There is no short form of this
-o --others str A string of other things
");
// ... and now you have your arguments nicely wrapped up:
print arg("alpha"); // returns the value of -a or --alpha
print arg("a"); // same thing
print arg(); // returns the whole parsed array
print arg(1); // returns the first unnamed argument
print arg(2); // returns the second unnamed argument
print arg("douglas",42); // value of "douglas", or a reasonable default
All you need to do is write the argument list as a multiline string. Four columns, looks like a help, but arg()
parses your lines and finds out the arguments automatically.
Separate columns by two or more spaces - just like you would anyway.
Once parsed, each item will be represented by an array of fields, named char, word, type and help, respectively. If there's no short (char) or long (word) version for a parameter, just use a dash. Not for both, obviously.
Types are what they seem: bool means there's no value after the parameter; it's false if missing, true if present. The int and str types mean there must be a value, and int makes sure it's an integer. Optional parameters are not supported. Values can be separated by space or equal sign (i.e. "-a=4" or "-a 4")
After this first call, you have all your arguments neatly organized in a structure (dump it, you'll see) and you can query their values by name or number.
Function arg() has a second parameter for defaults so you'll never have to worry about missing values.
arg()
function itselffunction arg($x="",$default=null) {
static $arginfo = [];
/* helper */ $contains = function($h,$n) {return (false!==strpos($h,$n));};
/* helper */ $valuesOf = function($s) {return explode(",",$s);};
// called with a multiline string --> parse arguments
if($contains($x,"\n")) {
// parse multiline text input
$args = $GLOBALS["argv"] ?: [];
$rows = preg_split('/\s*\n\s*/',trim($x));
$data = $valuesOf("char,word,type,help");
foreach($rows as $row) {
list($char,$word,$type,$help) = preg_split('/\s\s+/',$row);
$char = trim($char,"-");
$word = trim($word,"-");
$key = $word ?: $char ?: ""; if($key==="") continue;
$arginfo[$key] = compact($data);
$arginfo[$key]["value"] = null;
}
$nr = 0;
while($args) {
$x = array_shift($args); if($x[0]<>"-") {$arginfo[$nr++]["value"]=$x;continue;}
$x = ltrim($x,"-");
$v = null; if($contains($x,"=")) list($x,$v) = explode("=",$x,2);
$k = "";foreach($arginfo as $k=>$arg) if(($arg["char"]==$x)||($arg["word"]==$x)) break;
$t = $arginfo[$k]["type"];
switch($t) {
case "bool" : $v = true; break;
case "str" : if(is_null($v)) $v = array_shift($args); break;
case "int" : if(is_null($v)) $v = array_shift($args); $v = intval($v); break;
}
$arginfo[$k]["value"] = $v;
}
return $arginfo;
}
// called with a question --> read argument value
if($x==="") return $arginfo;
if(isset($arginfo[$x]["value"])) return $arginfo[$x]["value"];
return $default;
}
I hope this helps a lot of lost souls out there, like I was. May this little function shed a light upon the beauty of not having to write a help AND a parser and keeping them in sync... Also, once parsed, this approach is lightning fast since it caches the variables so you can call it as many times as you want. It acts like a superglobal.
Also available on my GitHub Gist.
You can retrieve the "raw" arguments using $argv. See also: http://www.php.net/manual/de/reserved.variables.argv.php
Example: php file.php a b c
$argv
will contain "file.php", "a", "b"
and "c"
.
Use getopts
to get the parameters "parsed", PHP will do the dirty job for you. So it's probably the best way to go in your case as you want to pass the parameters with --options
.
Have a close look at http://www.php.net/manual/de/function.getopt.php
It describes the function well.
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