Interacting with the User
Pestle's a system for building structured command line programs. This means there are sub-systems and library functions available to help you with common tasks you'll need when writing command line programs. This document will explain how to give your pestle program command line arguments and options, and how to handle basic input and output via library functions.
Arguments
An argument is a value you pass to your command line program.
$ pestle.phar some-command Hello World "You are Great"
The above pestle invocation runs the some-command
program, and passes it three individual arguments, Hello, World, and the full string You are Great.
Pestle is just PHP under the hood. You could just grab the global $argv
array and access the raw arguments. However, pestle gives you a system for defining the sort or arguments you program takes, and receiving them in a less-global way.
In the PHP DocBlock for your pestle_cli
function, the @argument
lines define which arguments your program expects.
/**
* This is my program, there are many like it.
*
* @command some-command
* @argument my_first_arg Enter a Greeting [Hello]
* @argument another_arg Enter a Noun [World]
* @argument final_arg Enter a Compliment [You Are Great]
*/
function pestle_cli($argv)
{
output($argv['my_first_arg']);
output($argv['another_arg']);
output($argv['final_arg']);
}
If you ran the above program you would expect output similar to this
$ pestle.phar some-command Hello World "You are Great"
Hello
World
You are Great
An @argument
line requires three parts.
* @argument arg_id Description [Default]
The first part is an identifier -- arg_id
above. This identifier should be alpha numeric, no spaces, plus underscores and dashes. Stick to PHP variable naming rules (plus dashes) here and you'll be fine.
The second part is a a text description of the argument (Description
above). This is for humans to read.
The third part is a default value, surrounded by []
brackets (Default
above).
When you define your arguments this way, pestle will pass your pestle_cli
function an array ($argv
above) populated with key names that are your argument names, and key-values that are the passed in arguments.
Additionally, if a user fails to provide an argument, pestle will use your description to ask the user for a value. For example, if you invoke the above program with only two arguments
$ pestle.phar some-command Hello World
Enter a Compliment (You Are Great)]
pestle will ask for the third. If the user enters a value, pestle will populate the first argument to pestle_cli
with that value. If the user presses return without entering a value, pestle will use with the default value.
Options
Sometimes you want to allow the user to pass an optional value to your program. Unix has a long history of options to command line programs. If you do a lot of command line work you probably use options on ls
all the time.
$ ls -l
Unix commands have evolved to be more than a single letter (-l
above). For example, the following two curl commands are equivalent
$ curl -L http://example.com
$ curl --location http://example.com
The command line program curl has a short option syntax, and a long option syntax. Generally, single letter option names are preceded by a single dash (-
), and full-word option names are preceded by a double dash (--
).
Of course, unix being unix, you have the odd outlier like find
, where the full-word options use a single dash.
$ find . -name 'file.txt`
Pestle supports only the double dash option format. Similar to @arguments
, you can define your options via the @option
doc-block line of your pestle_cli
function.
/**
* Showing you options
*
* @command some-command
* @option some-option An Example Option
*/
function pestle_cli($argv, $options)
{
var_dump($options['some-option']);
}
An @option
line has two parts. The first, some-option
above, is an identifier for your option. This identifier should be alpha numeric, no spaces, plus underscores and dashes. Stick to PHP variable naming rules (plus dashes) here and you'll be fine.
The second part is a description of your option. This is for humans to read and understand what your option is for.
For options, pestle will pass a second array to the pestle_cli
function that's populated with your option keys. If you don't use an option, the key will be set to NULL
.
$ pestle.phar some-command
NULL
But if you do pass an option, its value will be set.
$ pestle.phar some-command --some-option foo
string(3) "foo"
$ pestle.phar some-command --some-option=foo
string(3) "foo"
Pestle supports both a space and an =
equal sign between the option identifier and the passed option value.
Callback Arguments
There's one advanced feature of the @arguments
directive we haven't discussed yet. That's the @callback
argument.
A @callback
argument allows you to invoke a custom function that will ask users for their argument value.
function someLocalFunction() {
return 'calculated-value';
}
/**
* Showing you @callback arguments
*
* @command some-command
* @argument identifier @callback someLocalFunction
*/
function pestle_cli($argv, $options)
{
output($argv['identifier']);
}
A @callback
argument still requires a PHP identifier (identifier
) above. However, instead of a description, the second part should be @callback
-- this lets pestle know it's dealing with a callback argument. The third part of a @callback
argument, someLocalFunction
above, is a PHP function available in the local scope.
With the above configuration, if a user fails to pass a value for argument, pestle will call someLocalFunction
and use its return value to populate the arguments array pestle passes to the pestle_cli
function.
Input and Output Functions
The default @argument
and @option
mechanisms are, by themselves, often enough to give your program enough user interface to get its job done. For those commands where you need/want additional input or output, pestle provides a number of importable functions.
These are particularly useful when implementing @callback
arguments, but can be used anywhere you'd like in your program.
output
The output function is similar to PHP's print
and echo
in that it will allow you to send output to a user's terminal.
pestle_import('Pulsestorm\Pestle\Library\output');
//...
output("Hello World");
# prints "Hello World\n"
The output
function accepts multiple arguments -- each one will be send to a user's terminal.
pestle_import('Pulsestorm\Pestle\Library\output');
//...
output("Hello", "World");
// prints "HelloWorld"
The output
function also accepts arrays, and will var_dump
their contents.
pestle_import('Pulsestorm\Pestle\Library\output');
//...
$array = [1,2,3];
output($array);
// prints
// array(3) {
// [0]=>
// int(1)
// [1]=>
// int(2)
// [2]=>
// int(3)
// }
exitWithErrorMessage
When something goes wrong with your program, sometimes it's best to throw up your hands and just leave. In other words, exit
the program. The exitWithErrorMessage
function allows to you
- Send a message to your terminal's STDERR stream (i.e. display an error in the user's terminal)
- Exit the program.
pestle_import('Pulsestorm\Pestle\Library\exitWithErrorMessage');
//...
if($badSceneMan) {
exitWithErrorMessage("ERROR: something bad happened, we're bailing");
}
input
If you want to ask your user a question, and then process their answer, use the input
function.
pestle_import('Pulsestorm\Pestle\Library\exitWithErrorMessage');
//...
$answer = input('How old are you?', 35);
output("Wow, you don't look a day over ", $answer - 8);
The first argument to input
is the question you want to ask your user. The second argument is the default value to use if someone just presses return instead of entering a value.
Use this function with care -- once you require input from a user your program can't be used in more complex shell scripts (without a human there to press the buttons). Ideally, limit your use of the input
function to the @callback
arguments described earlier in this document.