PHP Command Line Arguments and Options

后端 未结 2 1608
没有蜡笔的小新
没有蜡笔的小新 2020-12-19 10:20

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 arra

2条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-19 10:28

    Arguments, made easy

    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
    
    

    Explanation

    • 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.

    The arg() function itself

    function 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.

提交回复
热议问题