zendframework/zf2 — pull request #5713 by nicktacular (2014-01-12 22:28:53+00:00)
Title: Adding Zend\Console\Getopt option callback hooks

Based on some `@todo` annotations present in this class, I've added the ability to use callbacks when options are parsed. This feature addresses several of these `@todo` annotations.

## (1) Triggering callbacks for options when present

You can now trigger a callback for any option that is present. For example, suppose you wish to trigger a callback when the option `apples` is passed, either by it's short form `a` or by it's alias `apple`. Here is how you could do this:

```php
$opts = new Getopt(array(
'a|apple|apples=s' => 'Specify a type of apple you want to eat.'
));

$opts->setOptionCallback('apple', function($value){
echo "You want a $value apple!";
});
```

As soon as you call `$opts->parse()` the callback will be called assuming you passed `-a Gala`, `--apple=Gala`, or `--apples=Gala` on the command line. Furthermore, the value "Gala" will be passed by value to the first callback parameter.

## (2) Invalidating usage by returning `false`

Using a callback, you can return false to indicate that there is an issue with the way an option was used. Perhaps there is a dependance on some other value that must be present. For example:

```php
$opts = new Getopt(array(
'fruit|f-s' => 'The kind of fruit you would like to eat.',
'a|apple|apples-s' => 'Specify a type of apple you want to eat.'
));

$opts->setOptionCallback('fruit', function($value, $opts){
if (null === ($apple = $opts->getOption('apple'))) {
return false;
//you could also just throw a Exception\RuntimeException here, too, if you want more specificity
}

echo "You like apples, specifically $apple.";
});
```

Notice that you can specify a 2nd argument to the callback which is the instance of `Getopt` you're currently working with. This allows you to check on other command line parameters, should you need to.

This also accomplishes conditionally required parameters from the command line. Here, both options are technically optional, but specifying `--fruit=apple` will trigger the `apple` requirement. You can use callbacks to accomplish conditional logic in this manner.

## Other `@todo` requests

`Handle flags that implicitly print usage message, e.g. --help`: this can easily be accomplished using a callback. Since `Getopt` class should never be dealing without output, the way to deal with this would be to attach a callback that throws the `Exeption\RuntimeException` method with the usage information. You can then use exception handling to print out the error message in the existing error handling for console apps:

```php
try {
$opts = new Getopt(/* params */);
$opts->setOptionCallback('help', function($val, $opts){
throw new Exception\RuntimeException('Usage:', $opts->getUsageMessage());
});
$opts->parse();
} catch (Exception\RuntimeException $e) {
echo $e->getMessage() . PHP_EOL;
echo $e->getUsageMessage();
exit(1);
}
```

`Enable user to specify header and footer content in the help message.`: This class does not deal with output. The previous example could simply add header/footer information to the printing of the exception message and usage message wherever appropriate. This would simply be the programmers choice.

---------------------------
Excerpt of class doc block:
```
*
* @todo Handle flags that implicitly print usage message, e.g. --help
*
* @todo Enable user to specify header and footer content in the help message.
*
* @todo Feature request to handle option interdependencies.
* e.g. if -b is specified, -a must be specified or else the
* usage is invalid.
*
* @todo Feature request to implement callbacks.
* e.g. if -a is specified, run function 'handleOptionA'().
```