PHP Command Line Interface (CLI) options parser -- CommandLine::parseArgs($argv)

2009-08-21

Here's a utility class that supports Linux style arguments for command line execution of PHP. It is high-performance (no regular expressions) and provides a flexible, simple and convenient syntax.

>> View source on Github

<?php
/**
 * CommandLine class
 *
 * Command Line Interface (CLI) utility class.
 *
 * @author              Patrick Fisher <patrick@pwfisher.com>
 * @since               August 21, 2009
 * @see                 http://github.com/pwfisher/CommandLine.php
 */
class CommandLine
{
    public static $args;

    /**
     * PARSE ARGUMENTS
     * 
     * This command line option parser supports any combination of three types
     * of options (switches, flags and arguments) and returns a simple array.
     * 
     * [pfisher ~]$ php test.php --foo --bar=baz
     *   ["foo"]   => true
     *   ["bar"]   => "baz"
     * 
     * [pfisher ~]$ php test.php -abc
     *   ["a"]     => true
     *   ["b"]     => true
     *   ["c"]     => true
     * 
     * [pfisher ~]$ php test.php arg1 arg2 arg3
     *   [0]       => "arg1"
     *   [1]       => "arg2"
     *   [2]       => "arg3"
     * 
     * [pfisher ~]$ php test.php plain-arg --foo --bar=baz --funny="spam=eggs" --also-funny=spam=eggs \
     * > 'plain arg 2' -abc -k=value "plain arg 3" --s="original" --s='overwrite' --s
     *   [0]       => "plain-arg"
     *   ["foo"]   => true
     *   ["bar"]   => "baz"
     *   ["funny"] => "spam=eggs"
     *   ["also-funny"]=> "spam=eggs"
     *   [1]       => "plain arg 2"
     *   ["a"]     => true
     *   ["b"]     => true
     *   ["c"]     => true
     *   ["k"]     => "value"
     *   [2]       => "plain arg 3"
     *   ["s"]     => "overwrite"
     *
     * @author              Patrick Fisher <patrick@pwfisher.com>
     * @since               August 21, 2009
     * @see                 http://github.com/pwfisher/CommandLine.php
     *                      #81042 function arguments($argv) by technorati at gmail dot com, 12-Feb-2008
     *                      #78651 function getArgs($args) by B Crawford, 22-Oct-2007
     * @usage               $args = CommandLine::parseArgs($_SERVER['argv']);
     */
    public static function parseArgs($argv)
    {
        $argv                           = $argv ? $argv : $_SERVER['argv'];
        array_shift($argv);
        $out                            = array();

        foreach ($argv as $arg)
        {
            // --foo --bar=baz
            if (substr($arg, 0, 2) === '--')
            {
                $eqPos                  = strpos($arg, '=');

                // --foo
                if ($eqPos === false)
                {
                    $key                = substr($arg, 2);
                    $value              = isset($out[$key]) ? $out[$key] : true;
                    $out[$key]          = $value;
                }

                // --bar=baz
                else
                {
                    $key                = substr($arg, 2, $eqPos - 2);
                    $value              = substr($arg, $eqPos + 1);
                    $out[$key]          = $value;
                }
            }

            // -k=value -abc
            else if (substr($arg, 0, 1) === '-')
            {
                // -k=value
                if (substr($arg, 2, 1) === '=')
                {
                    $key                = substr($arg, 1, 1);
                    $value              = substr($arg, 3);
                    $out[$key]          = $value;
                }
                // -abc
                else
                {
                    $chars              = str_split(substr($arg, 1));
                    foreach ($chars as $char)
                    {
                        $key            = $char;
                        $value          = isset($out[$key]) ? $out[$key] : true;
                        $out[$key]      = $value;
                    }
                }
            }

            // plain-arg
            else
            {
                $value                  = $arg;
                $out[]                  = $value;
            }
        }

        self::$args                     = $out;

        return $out;
    }

    /**
     * GET BOOLEAN
     */
    public static function getBoolean($key, $default = false)
    {
        if (!isset(self::$args[$key]))
        {
            return $default;
        }
        $value                          = self::$args[$key];

        if (is_bool($value))
        {
            return $value;
        }

        if (is_int($value))
        {
            return (bool)$value;
        }

        if (is_string($value))
        {
            $value                      = strtolower($value);
            $map = array(
                'y'                     => true,
                'n'                     => false,
                'yes'                   => true,
                'no'                    => false,
                'true'                  => true,
                'false'                 => false,
                '1'                     => true,
                '0'                     => false,
                'on'                    => true,
                'off'                   => false,
            );
            if (isset($map[$value]))
            {
                return $map[$value];
            }
        }

        return $default;
    }
}
And here is a compacted version:
<?php
/**
 * parseArgs Command Line Interface (CLI) utility function.
 * @author              Patrick Fisher <patrick@pwfisher.com>
 * @see                 http://github.com/pwfisher/CommandLine.php
 */
function parseArgs($argv) {
    $argv = $argv ? $argv : $_SERVER['argv']; array_shift($argv); $o = array();
    foreach ($argv as $a) {
        if (substr($a, 0, 2) == '--') { $eq = strpos($a, '=');
            if ($eq !== false) { $o[substr($a, 2, $eq - 2)] = substr($a, $eq + 1); }
            else { $k = substr($a, 2); if (!isset($o[$k])) { $o[$k] = true; } } }
        else if (substr($a, 0, 1) == '-') {
            if (substr($a, 2, 1) == '=') { $o[substr($a, 1, 1)] = substr($a, 3); }
            else { foreach (str_split(substr($a, 1)) as $k) { if (!isset($o[$k])) { $o[$k] = true; } } } }
        else { $o[] = $a; } }
    return $o;
}

The compact version is very convenient for pasting into single-file scripts. It is totally equivalent to the airier version above.

Enjoy!

- Patrick


Comments