The PHP CLI CMD library. Helps you create well-structured PHP CLI apps quickly and easily.
This library supports setting up options and arguments, subcommands and offers an integrated command help. Use the color or progress bar helpers to visualize important outputs.
The simplest way of installing ist to refer to the sources on packagist.
composer require stefaminator/php-cli-cmd
Let's start by creating a new php file called cli-app-helloworld.php
and require composers autoloader.
Create a custom class by extending Stefaminator\Cli\App
and implement the required setup
method
which must return an instance of Stefaminator\Cli\Cmd
. In the following example we created a root Cmd
and put the lines to execute for that root command into the run
method.
Finally, call the apps run()
method and feel the magic.
(You can will this example here: examples/cli-app-helloworld.php)
<?php
/** Please do not forget to require composers autoloader here */
use Stefaminator\Cli\App;
use Stefaminator\Cli\Cmd;
(new class extends App {
public function setup(): Cmd {
return (new class extends Cmd {
public function init(): void {
}
public function run(): void {
echo "Hello world";
echo "\n";
}
});
}
})->run();
If you execute that script from commandline you will see:
# php cli-app-helloworld.php
Hello World
Uhh, that was a lot of code for such a simple output, and you may think: "I can do the same with less code" - Yes, I believe you can!
Ok, let's start with a simple example to add some options to our app!
Let's add one help flag option (--help
or -h
) to output the built in command help,
and one name option to be able to say hello to a given name (i.e. --name=Stefaminator
).
<?php
use Stefaminator\Cli\App;
use Stefaminator\Cli\Cmd;
use Stefaminator\Cli\Color;
(new class extends App {
public function setup(): Cmd {
return (new class extends Cmd {
public function init(): void {
$this
->addOption('h|help', [
'description' => 'Displays the command help.'
])
->addOption('name:', [
'description' => 'Name option. This option requires a value.',
'isa' => 'string',
'default' => 'World'
]);
}
public function run(): void {
if ($this->hasProvidedOption('help')) {
$this->runHelp();
return;
}
$name = $this->getProvidedOption('name');
self::eol();
self::echo(sprintf('Hello %s', $name), Color::FOREGROUND_COLOR_YELLOW);
self::eol();
self::eol();
}
public function help(): void {
echo '' .
' This is the custom help for ' . Color::green('cli-app-options') . ' command. ' . self::EOL .
' Please use the --name option to pass your name to this command and you will be greeted personally. ' . self::EOL .
' ' . self::EOL .
' ' . Color::green('php cli-app-options.php --name="great Stefaminator"') . self::EOL;
}
});
}
})->run();
Options should be added within the Cmd::init()
method according to the following scheme:
$this->addOption($specString, $configArray);
The addOption()
method is chainable, so you may add options like this:
$this
->addOption($specString1, $configArray1)
->addOption($specString2, $configArray2);
Please note that option parsing based on https://github.com/c9s/GetOptionKit. Both the option specs and the option value validation based on that great library. So maybe check out their documentation first if you have any questions or issues with these features.
Option specs
Use the $specString
(first argument of addOption
method) to define the options
long and/or short name and use the qualifiers :
, +
and ?
to determine if it should be a flag, required, multiple or optional value.
h|help flag option with single char option name (-h) and long option name (--help).
n|name: option require a value (-n=Stefaminator or --name="great Stefaminator").
i|input+ option with multiple values (-i=file1 -i=file2).
o|output? option with optional value (--output or -o=output.txt)
v single character only option (-v)
dir long option name (--dir)
Option config
Specify more option attributes via $configArray
(second argument of addOption
method). Here is a list of possible keys:
description string The description string is used in builtin command help
isa string The option value type to validate the input (see: Option value validation)
regex string A regex to validate the input value against (in case of isa=regex)
default mixed The options default value
incremental bool Typically used for verbose mode (with -vvv the value will be 3)
Option value validation
Possible values for the option configs isa
key.
string To ensure the given value is a string.
number To ensure the given value is a number.
boolean To ensure the given value is a boolean (true, false, 0, 1).
file To ensure the given value is an existing file.
date To ensure the given value is a valid date (Y-m-d).
url To ensure the given value is a valid url.
email To ensure the given value is a valid email.
ip To ensure the given value is a valid ip(v4/v6).
ipv4 To ensure the given value is a valid ipv4.
ipv6 To ensure the given value is a valid ipv6.
regex Validate the value against a custom regex (specified in regex key).
The values of provided options may be catched within the Cmd::run()
method using one of the following calls:
/**
* Returns true if a value for the given option name is present.
* @param string $key Long option name if present, otherwise short option char
* @return bool
*/
$this->hasProvidedOption($key);
/**
* Returns the value for the given option name.
* @param string $key Long option name if present, otherwise short option char
* @return mixed
*/
$value = $this->getProvidedOption($key);
/**
* Returns an array of key value pairs with all present option values.
* @return array
*/
$all = $this->getAllProvidedOptions();
/**
* Holds the original OptionResult of c9s/GetOptionKit library
* @var OptionResult|null
*/
$this->optionResult;
Arguments are generally always accepted and not validated by configuration. Any endpoint has to decide if it processes arguments and must validate them by itself. However, if you accept arguments you may want to make them visible and explained in help output. Therefore, and only therefore, you may declare it like explained here.
Arguments should be added within the Cmd::init()
method according to the following scheme:
$this->addArgument($specString, $configArray);
The addArgument()
method is chainable, so you may combine it with addOption()
and add arguments like this:
$this
->addOption($specString1, $configArray1)
->addOption($specString2, $configArray2)
->addArgument($specString3, $configArray3);
Argument specs
Use the $specString
(first argument of addArgument
method) to give the argument a meaningful name.
Argument config
Specify more argument attributes via $configArray
(second argument of addArgument
method).
Here is a list of possible keys:
description string The description string is used in builtin command help
multiple bool The multiple flag is used in builtin command help to mark it as multiple (works only for the last declared arg)
The values of provided options may be catched within the Cmd::run()
method using one of the following calls:
/**
* Returns an indexed array of provided arguments.
* @return array
*/
$args = $this->arguments();
As explained above, it doesn't matter if the arguments had been declared via addArgument()
.
In contrast to options, which are only present after successful validation, arguments are present whenever they have been typed.
The following example (cli-app-subcommands.php
) shows one root command that outputs the root command help,
one subcommand show
that outputs the command help for the show command,
and two subcommands for the show
command (hello
and phpversion
).
php cli-app-subcommands.php // Outputs command help for root command
php cli-app-subcommands.php show // Outputs command help for the "show" command
php cli-app-subcommands.php show hello // Outputs "Hello World"
php cli-app-subcommands.php show hello -h // Outputs command help for the "show hello" command
php cli-app-subcommands.php show hello --name=me // Outputs "Hello me"
php cli-app-subcommands.php show phpversion // Outputs the current php version of your cli
Ok, here is the code:
<?php
use Stefaminator\Cli\App;
use Stefaminator\Cli\Cmd;
use Stefaminator\Cli\Color;
(new class extends App {
public function setup(): Cmd {
return (
new class extends Cmd {
public function init(): void {
}
public function run(): void {
$this->runHelp();
}
})
->addChild((new class('show') extends Cmd {
public function init(): void {
$this
->setDescription(
'This command is used to show something. Take a look at the subcommands.'
);
}
public function run(): void {
$this->runHelp();
}
})
->addChild((new class('hello') extends Cmd {
public function init(): void {
$this
->setDescription(
'Displays hello world.'
)
->addOption('h|help', [
'description' => 'Displays the command help.'
])
->addOption('name:', [
'description' => 'Name option. This option requires a value.',
'isa' => 'string',
'default' => 'World'
]);
}
public function run(): void {
if ($this->hasProvidedOption('help')) {
$this->runHelp();
return;
}
$name = $this->getProvidedOption('name');
self::eol();
self::echo(sprintf('Hello %s!', $name), Color::FOREGROUND_COLOR_CYAN);
self::eol();
self::eol();
}
}))
->addChild((new class('phpversion') extends Cmd {
public function init(): void {
$this
->addOption('h|help', [
'description' => 'Displays the command help.'
])
->setDescription(
'Displays the current php version of your cli.'
);
}
public function run(): void {
if ($this->hasProvidedOption('help')) {
$this->runHelp();
return;
}
self::eol();
self::echo(' Your PHP version is:', Color::FOREGROUND_COLOR_YELLOW);
self::eol();
self::echo(' ' . PHP_VERSION);
self::eol();
self::eol();
}
}))
);
}
})->run();
As you might have already recognized a subcommand has been configured by calling the Cmd::addChild()
method.
That method accepts another Cmd
object which may also have one or more child commands assigned to it.