<?php
/**
* Get Options Class
* Pure PHP OOP implementation of getopt
* @author chris@fuelforthefire.ca
* @copyright Fuel for the Fire
* @version 0.2
* @date 2013-06-17
*/
/**
* Get Options
* Recieves array of arguments and evaluates them
* @name GetOpts
* @package cli
*/
class GetOpts
{
/**
* Arguments
* internal storage of the arguments to parse
* @var array
* @access private
*/
private $aArgs;
/**
* Return Unknown Flag
* If set unknown options will be returned as '?'
* @var bool
* @access private
*/
private $bShowUnknown;
/**
* Argument Count
* The number of arguments passed to the class
* @var integer
* @access private
*/
private $iArgCnt;
/**
* Argument Index
* last index in the argument array we looked at
* @var int
* @access private
*/
private $iArgIndex;
/**
* Options
* an array of acceptable short options (-o)
* @var array
* @access private
*/
private $aOptions;
/**
* Long Options
* an array of acceptable long options (--option)
* @var mixed
*/
private $aLongOpts;
/**
* Constructor
* Sets up the arguments to be evaluated
* @name GetOpts
* @param array $in_arguments Arguments to evaluate
* @param string $in_options Options to look for
* @param string $in_longopts Long options to look for
* @param bool $in_return_unknown Should we return unknown arguments?
* @return GetOpts
*/
public function __construct(array $in_arguments, /*string*/ $in_options, array $in_longopts = array(), /*bool*/ $in_return_unknown = false)
{
// Store and count arguments
$this->aArgs = $in_arguments;
$this->iArgCnt = count($this->aArgs);
// Init last index
$this->iArgIndex = null;
// Store short and long options
$this->aOptions = array();
$this->aLongOpts = array();
$this->parseOptions($in_options, $in_longopts);
// Check for unknown arguments?
$this->bShowUnknown = $in_return_unknown;
}
/**
* Next Option
* returns the next option in the list of arguments
* @name next
* @access public
* @return array|false 0 => option, 1 => value
*/
public function next()
{
// Check if we've run before
if(is_null($this->iArgIndex))
{
// Skip the first argument if it's the name of the current script
$this->iArgIndex = (isset($_SERVER['argv'][0]) &&
$_SERVER['argv'][0] == $_SERVER['SCRIPT_NAME']) ?
0 :
-1;
}
// Check if we're done
if(++$this->iArgIndex >= $this->iArgCnt)
{
return null;
}
// Check if it's a long option
if($this->aArgs[$this->iArgIndex]{0} == '-' && $this->aArgs[$this->iArgIndex]{1} == '-')
{
// If there's an equal sign in the argument
if($iPos = strpos($this->aArgs[$this->iArgIndex], '='))
{
$sArg = substr($this->aArgs[$this->iArgIndex], 2, ($iPos-2));
$sVal = substr($this->aArgs[$this->iArgIndex], $iPos+1);
}
else
{
$sArg = substr($this->aArgs[$this->iArgIndex], 2);
$sVal = null;
}
// Is it in the approved list
if(isset($this->aLongOpts[$sArg]))
{
// Does the option have an optional parameter?
if($this->aLongOpts[$sArg])
{
// If we already have it
if(!is_null($sVal))
{
return array($sArg, $sVal);
}
else
{
return array($sArg, $this->aArgs[++$this->iArgIndex]);
}
}
else
{
return array($sArg, false);
}
}
else
{
// If we're allowed to show unknowns
if($this->bShowUnknown)
{
return array('?', $this->aArgs[$this->iArgIndex]);
}
// Else try to get the next option
else
{
return $this->next();
}
}
}
// Check that the first character of the argument is '-' or '/'
else if(in_array($this->aArgs[$this->iArgIndex]{0}, array('-', '/')))
{
// Store the argument
$sArg = $this->aArgs[$this->iArgIndex]{1};
// We have an option, is it in the approved list?
if(isset($this->aOptions[$sArg]))
{
// Does the option have an optional parameter?
if($this->aOptions[$sArg])
{
// The argument does not contain the value, so get it from the next argument
if(strlen($this->aArgs[$this->iArgIndex]) == 2)
{
return array($sArg, $this->aArgs[++$this->iArgIndex]);
}
// Else, pull out the value from the argument
else
{
return array($sArg, substr($this->aArgs[$this->iArgIndex], 2));
}
}
// Else it's set or not set
else
{
return array($sArg, false);
}
}
else
{
// If we're allowed to show unknowns
if($this->bShowUnknown)
{
return array('?', $this->aArgs[$this->iArgIndex]);
}
// Else try to get the next option
else
{
return $this->next();
}
}
}
else
{
// If we're allowed to show unknowns
if($this->bShowUnknown)
{
return array('?', $this->aArgs[$this->iArgIndex]);
}
// Else try to get the next option
else
{
return $this->next();
}
}
}
/**
* Parse Options
* parses the options passed to the class into an array and stores them locally
* @name parseOptions
* @access private
* @param string $in_options The options passed to the class
* @param array $in_longopts The long options passed to the class
* @return void
*/
private function parseOptions(/*string*/ $in_options, array $in_longopts)
{
// Parse the short options
$aOpts = str_split($in_options);
$iCnt = count($aOpts);
for($i = 0; $i < $iCnt; ++$i)
{
// If the option needs an argument
if($aOpts[$i+1] == ':') {
$this->aOptions[$aOpts[$i]] = true;
++$i;
} else {
$this->aOptions[$aOpts[$i]] = false;
}
}
// Parse the long options
foreach($in_longopts as $sOpt)
{
// Get the length of the string
$iLen = strlen($sOpt);
// If the option needs an argument
if(':' == $sOpt[$iLen-1]) {
$this->aLongOpts[substr($sOpt, 0, -1)] = true;
} else{
$this->aLongOpts[$sOpt] = false;
}
}
}
}