Class it:

/**
 * Parse command line options with Usage given as template and return assoc array.
 * @param $usage Usage parsed to determine options, example see below.
 * @param $p['optbeforearg'] Stop parsing options when first argument is encountered
 * @param $p['noexit'] Just return false in case of help or bad usage
 * @return Associative array of options, key 'args' for optional non-option args
 *
 * Usage: myprogram.php [OPTIONS] PATTERN [MOREARGS]
 *  -s, --short      Use short ouput
 *  -f, --file=FILE  Use FILE for input [foo.txt]
 *  -x EXTENSION     Ignore EXTENSION
 * Mandatory arguments from the Usage: line are returned under their (lowercased!) name.
 * Option text must be indented; if long and short option present, value is stored in long one.
 * For long opts with arguments, = is mandatory in usage. Defaults in [ ] at end of line
 * Two or more blanks must be in front of option explanation
 * Options without arguments store true or false under their key
 * Option --help or -h prints de-indented usage and exits (needs not be in usage)
 * Option --debug foo-bar will store bar in EDC('foo'). (needs not be in usage)
 * Option --verbose sets debug variable verbose for EDC('verbose', $bar). (must be in usage)
 */
static function getopt($usage, $p = array())
{
    $GLOBALS['it_stdin'] = array(
        'fd' => null,
        'args' => array(),
        'filename' => "",
        'line' => 0,
    );

    $result = array('args' => array());

    if ($indentation = it::match('^\s+', $usage))
        $usage = it::replace(array($indentation => "\n"), $usage);

    foreach(explode("\n", trim($usage)) as $usageline)
    {
        $shortoptname = $shortoptarg = $longoptname = $longoptarg = "";
        foreach (explode(',', $usageline, 2) as $optdesc)
        {
            $optdesc = trim($optdesc);
            if ($matches = (array)it::match('^--(\w[\w-]*)(=[A-Z])?', $optdesc))
                list($longoptname, $longoptarg) = $matches;
            else if ($matches = (array)it::match('^-(\w)( [A-Z])?', $optdesc))
                list($shortoptname, $shortoptarg) = $matches;
        }

        if (($default = it::match('\[(.*)\]\s*$', $usageline)) !== null)
        {
            if ($longoptarg || $shortoptarg)
                $defaults[$longoptname ? $longoptname : $shortoptname] = it::replace(array('^default:\s*' => ""), trim($default));
            else if (($longoptname || $shortoptname) && it::match('^\w+$', $default))
                it::error('defaults for boolean arguments not supported!');
        }

        if ($longoptname || $shortoptname)
        {
            if ($longoptname && ($shortoptname || $shortoptname === "0"))
            {
                if ($alias[$shortoptname])
                    it::error("getopt: short option -$shortoptname is used twice: --{$alias[$shortoptname]} and --$longoptname!");
                $alias[$shortoptname] = $longoptname;
            }

            $witharg[$longoptname ? $longoptname : $shortoptname] = $longoptarg || $shortoptarg;
        }
    }
    $witharg['debug'] = true;

    $argsdesc = trim(it::replace(array("\n.*" => "", "^\S+\s+\S+\s*" => ""), trim($usage)));
    $mandatoryargs = it::match('\S+', it::replace(['\[.*?\]' => ''], $argsdesc), ['all' => true]);
    $optionalargs = it::match('\[((?!OPTIONS\]).*?)\]', $argsdesc, ['all' => true]);
    if ($mandatoryargs && !it::match("Usage:", $usage))
        it::error("Usage string must contain 'Usage:'");

    foreach (array_slice($_SERVER['argv'], 1) as $arg)
    {
        if ($eat)
            $result[array_shift($eat)] = $arg;
        else if (!$noopts && $arg == "--")
            $noopts = true;
        else if (!$noopts && ($matches = (array)it::match('^--(\w[\w-]*)(=.*)?', $arg)))
        {
            list($optname, $val) = $matches;
            if (!isset($witharg[$optname]) || isset($val) && !$witharg[$optname])
                $err = true;
            else if($witharg[$optname] && !$val)
                $eat[] = $optname;
            else
                $result[$optname] = $val ? substr($val, 1) : true;
        }
        else if (!$noopts && (($letters = it::match('^-(\w+)', $arg)) || $letters === "0"))
        {
            foreach (explode("\n", trim(chunk_split($letters, 1, "\n"))) as $letter)
            {
                $optname = $alias[$letter] ? $alias[$letter] : $letter;
                if ($witharg[$optname] && it::match('=', $arg))
                    $result[$optname] = it::match('=(.*)', $arg);
                else if ($witharg[$optname])
                    $eat[] = $optname;
                else if (!isset($witharg[$optname]))
                    $err = true;
                else
                    $result[$optname] = true;
            }
        }
        else if($mandatoryargs)
            $result[strtolower(array_shift($mandatoryargs))] = $seenarg = $arg;
        else
            $result['args'][] = $seenarg = $arg;

        if ($p['optbeforearg'] && $seenarg)
            $noopts = true;
    }

    if ($err || $eat || $result['h'] || $result['help'] || $mandatoryargs || (!$optionalargs && $result['args']))
    {
        if (is_resource($out = $result['h'] || $result['help'] ? STDOUT : STDERR))
            fputs($out, trim($usage) . "\n");
        return $p['noexit'] ? false : exit(1);
    }

    if ($result['debug'])
        it_debug::set($result['debug']);

    $GLOBALS['it_stdin']['args'] = $result['args'] ? $result['args'] : array("-");

    if ($result['verbose'])
        $GLOBALS['debug_verbose']++;

    return $result + (array)$defaults;
}