Managing command line options
Some background
Options are used to provide extra information to tune or customize the execution of a program. In case it wasn't clear, options are usually optional. A program should be able to run just fine with no options whatsoever. Pick a random program from the Unix or GNU toolsets. Can it run without any options at all and still make sense? The main exceptions are find, tar, and dd--all of which are mutant oddballs that have been rightly criticized for their non-standard syntax and confusing interfaces.
Lots of people want their programs to have "required options". Think about it. If it's required, then it's not optional! If there is a piece of information that your program absolutely requires in order to run successfully, that's what arguments are for.
As an example of good command-line interface design, consider the humble cp utility, for copying files. It doesn't make much sense to try to copy files without supplying a destination and at least one source. Hence, cp fails if you run it with no arguments. However, it has a flexible, useful syntax that does not require any options at all:
$ cp SOURCE DEST $ cp SOURCE ... DEST-DIR
You can get pretty far with just that. Most cp implementations provide a bunch of options to tweak exactly how the files are copied: you can preserve mode and modification time, avoid following symlinks, ask before clobbering existing files, etc. But none of this distracts from the core mission of cp, which is to copy either one file to another, or several files to another directory.
Adding options with Console_CommandLine
To add options to your parser, just create the parser as explained in the previous section and use the Console_CommandLine::addOption() method.
The Console_CommandLine::addOption() method takes two arguments:
-
the option name: a string that will be used to access the
option in the result object. For example if you name your option
foo, you will access to the result object like this:
$result->options['foo']
; - the options parameters: an array of various informations, as explained below.
name | type | required | description | example |
---|---|---|---|---|
short_name | string | yes, if no long_name given | the option short name | -o |
long_name | string | yes, if no short_name given | the option long name | --orientation |
description | string | no, but recommended for the help message | a description for the option | orientation of the page: ltr (default) or rtl |
action | string | no, default to "StoreString" | the option action (see next section for details) | StoreString |
default | mixed | no | the option default value | ltr |
choices | array | no, only relevant for options that expect argument(s) | list of possible values for the option | array('ltr', 'rtl') |
list | array | no, only relevant for options that use the "List" action | list of values to display | array('blue', 'green', 'yellow') |
add_list_option | boolean | no, default to FALSE | this property is only relevant when the choices property is set, if set to TRUE the parser will generate an additional option to list the choices (eg. --list-foo). | TRUE |
help_name | string | no, if not given it will default to the option name | the name to display in the option help line | page_orientation (the help ligne will be: --orientation=page_orientation) |
Adding commandline options
<?php
require_once 'Console/CommandLine.php';
$parser = new Console_CommandLine(array(
'description' => 'A useful description for your program.',
'version' => '0.0.1', // the version of your program
));
// Adding a simple option that takes no argument and that tell our program to
// turn on verbose output:
$parser->addOption(
'verbose',
array(
'short_name' => '-v',
'long_name' => '--verbose',
'description' => 'turn on verbose output',
'action' => 'StoreTrue'
)
);
// Adding an option that will store a string
$parser->addOption(
'orientation',
array(
'short_name' => '-o',
'long_name' => '--orientation',
'description' => 'orientation of the page, "ltr" (default) or "rtl"',
'action' => 'StoreString',
'default' => 'ltr',
'help_name' => 'page_orientation'
)
);
try {
$result = $parser->parse();
print_r($result->options);
} catch (Exception $exc) {
$parser->displayError($exc->getMessage());
}
?>
Now if the user type:
$ <yourprogram> -vo rtl
or (equivalent):
$ <yourprogram> --verbose --orientation=rtl
The output of the above script will be:
Array ( [verbose] => 1 [orientation] => rtl [help] => [version] => )
Options actions
Actions tell the parser how to handle option values, among other things they tell the parser if the option expects a value or not and how to store this value in the result object.
StoreTrue
This action tells the parser to store the value true in the result object if the option is present in the command line, for example:
$ <yourprogram> -v
will store TRUE in $result->options['verbose']
,
assuming the option was defined like this:
<?php
$parser->addOption('verbose', array('short_name'=>'-v', 'action'=>'StoreTrue'));
$result = $parser->parse();
?>
StoreFalse
This action tells the parser to store the value false in the result object if the option is present in the command line, for example:
$ <yourprogram> -q
will store FALSE in $result->options['verbose']
,
assuming the option was defined like this:
<?php
$parser->addOption('verbose', array('short_name'=>'-q', 'action'=>'StoreFalse'));
$result = $parser->parse();
?>
StoreString
This action tells the parser that the option expects a value and to store this value as a string in the result object, for example:
$ <yourprogram> -o out.txt
will store the string "out.txt" in
$result->options['outfile']
,
assuming the option was defined like this:
<?php
$parser->addOption('outfile', array('short_name'=>'-o', 'action'=>'StoreString'));
$result = $parser->parse();
?>
StoreInt
This action tells the parser that the option expects a value and to store this value as an integer in the result object, for example:
$ <yourprogram> --width=500
will store the integer 500 in $result->options['width']
,
assuming the option was defined like this:
<?php
$parser->addOption('width', array('long_name'=>'--width', 'action'=>'StoreInt'));
$result = $parser->parse();
?>
StoreFloat
This action tells the parser that the option expects a value and to store this value as a float in the result object, for example:
$ <yourprogram> -l=0.3
will store the float 0.3 in $result->options['level']
,
assuming the option was defined like this:
<?php
$parser->addOption('level', array('short_name'=>'-l', 'action'=>'StoreFloat'));
$result = $parser->parse();
?>
Counter
This action tells the parser to increment the value in the result object each time it encounters the option in the command line, for example:
$ <yourprogram> -vvvv
or the equivalent:
$ <yourprogram> -v -v -v --verbose
will store the integer 4 in
$result->options['verbose_level']
,
assuming the option was defined like this:
<?php
$parser->addOption('verbose_level', array(
'short_name' => '-v',
'long_name' => '--verbose',
'action' => 'Counter'
));
$result = $parser->parse();
?>
Help
This action tells the parser to display the help message if it encounters the option in the command line, most of the time you won't need this since it is handled by Console_CommandLine internally.
Version
This action tells the parser to display the program version if it encounters the option in the command line, as for Help action, chances are that you won't need this since it is handled by Console_CommandLine internally.
Password
This action allows the user to either type the password on the commandline or to be prompted for it (will not echo on unix systems), some examples:
<?php
$parser->addOption('password', array('short_name'=>'-p', 'action'=>'Password'));
$result = $parser->parse();
?>
$ <yourprogram> -ps3cret
will store the string "s3ecret" in
$result->options['password']
whereas:
$ <yourprogram> -p
will "prompt" the user for entering his/her password
without echoing it, and will store "s3ecret" in
$result->options['password']
Callback
This action allows to specify a PHP callback to handle user input. The callback must be a php callable and must accept five arguments:
- the value of the option;
- the Console_CommandLine_Option_Callback instance
- the Console_CommandLine_Result instance
- the Console_CommandLine instance (the parser)
- an array of additional parameters that you specify when building your option.
Your callback function must return the modified (or not modified) value (the first argument).
All these arguments should give you enough flexibility to build complex callback actions.
If the callback is to a class method, then the method must be declared as a public.
Here is a simple example:
<?php
/**
* A simple encryption callback.
*
*/
function encryptCallback($value, $option, $result, $parser, $params=array())
{
if (!isset($params['salt'])) {
$params['salt'] = '';
}
return sha1($params['salt'] . $value);
}
require_once 'Console/CommandLine.php';
$parser = new Console_CommandLine();
$parser->addOption('encrypt', array(
'short_name' => '-e',
'long_name' => '--encrypt',
'action' => 'Callback',
'description' => 'encrypt the given value using sha1 + salt',
'callback' => 'encryptCallback',
'action_params' => array('salt' => 'x2897ZHKx7200j1__2')
));
try {
$result = $parser->parse();
echo $result->options['encrypt'] . "\n";
} catch (Exception $exc) {
$parser->displayError($exc->getMessage());
}
?>
Now if the user type:
$ <yourprogram> -e foobar
The output of the above script will be:
7f12da3b1c126d7a47745b09dc0040c92cee1700
List
a special action that simply output an array as a list.
<?php
$parser->addOption('list_colors', array(
'short_name' => '-l',
'long_name' => '--list-colors',
'action' => 'List',
'list' => array('blue', 'green', 'yellow')
));
$result = $parser->parse();
?>
$ <yourprogram> --list-colors
will display the list of colors separated by commas.