Console commands, command-line input parsing and terminal output for the IviPHP ecosystem.
iviphp/console provides a framework-independent foundation for creating CLI applications, registering commands, parsing arguments and options, displaying command help and returning process exit codes.
- PHP 8.2 or later
iviphp/contractsiviphp/support
composer require iviphp/console- Closure-backed console commands
- Custom command implementations
- Command aliases
- Hidden commands
- Positional argument parsing
- Long and short option parsing
- Boolean, string and integer option helpers
- Repeated options
- Standard output and error streams
- Optional ANSI terminal colors
- Automatic command listings
- Built-in help behavior
- Application version output
- Unknown-command suggestions
- Configurable exception handling
- Framework-independent contracts
ConsoleManager coordinates:
- command registration;
- command resolution;
- input parsing;
- terminal output;
- command execution;
- help pages;
- command listings;
- version output;
- exception handling;
- process exit codes.
Console is the public application-facing wrapper around ConsoleManager.
A command defines:
- a unique name;
- a description;
- optional aliases;
- a usage expression;
- whether it is hidden;
- execution logic.
ArgvInput parses an argv-compatible array into:
- executable script;
- command name;
- positional arguments;
- named options;
- original tokens.
ConsoleOutput writes regular messages to standard output and errors to standard error.
ANSI terminal decoration can be detected automatically or configured explicitly.
<?php
declare(strict_types=1);
use Ivi\Console\Console;
use Ivi\Console\ConsoleManager;
$manager = new ConsoleManager(
applicationName: 'My Application',
applicationVersion: '1.0.0'
);
$console = new Console($manager);<?php
declare(strict_types=1);
use Ivi\Console\Contracts\InputInterface;
use Ivi\Console\Contracts\OutputInterface;
$console->command(
name: 'hello',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
$output->writeln('Hello from IviPHP.');
return 0;
},
description: 'Display a greeting.'
);Run the command:
php console helloOutput:
Hello from IviPHP.
Command handlers must return an integer between 0 and 255.
The console manager provides common exit-code constants:
use Ivi\Console\ConsoleManager;
ConsoleManager::SUCCESS;
ConsoleManager::FAILURE;
ConsoleManager::INVALID;Their values are:
SUCCESS = 0
FAILURE = 1
INVALID = 2
Example:
$console->command(
name: 'project:check',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
$output->success('Project configuration is valid.');
return ConsoleManager::SUCCESS;
}
);Returning an exit code outside the supported range throws ConsoleException.
$console->command(
name: 'greet',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
$name = $input->argument(
0,
'Developer'
);
$output->writeln(
"Hello, {$name}."
);
return 0;
},
description: 'Greet a person.',
usage: 'greet [name]'
);Run it:
php console greet GaspardOutput:
Hello, Gaspard.
Retrieve all positional arguments:
$arguments = $input->arguments();Check whether an argument exists:
if ($input->hasArgument(0)) {
$name = $input->argument(0);
}Argument indexes start at zero.
The parser supports boolean long options:
php console build --verboseRetrieve the option:
$verbose = $input->option(
'verbose',
false
);Options may use an equals sign:
php console build --environment=production$environment = $input->option(
'environment',
'development'
);Options may also use the following token as their value:
php console build --environment productionOptions prefixed with --no- are stored as false.
php console build --no-cacheRetrieve the normalized option name:
$cacheEnabled = $input->booleanOption(
'cache',
true
);The value is false.
Single short options are supported:
php console build -v$verbose = $input->hasOption('v');Combined short flags are also supported:
php console build -abcThis creates the following options:
[
'a' => true,
'b' => true,
'c' => true,
]A short option may contain a value:
php console server:start -p=8080$port = $input->integerOption(
'p',
8000
);The special -- token stops option parsing.
Every following token becomes a positional argument.
php console inspect -- --example --verboseThe command receives:
[
'--example',
'--verbose',
]as positional arguments.
Repeated options are stored as arrays.
php console test --group=unit --group=integration$groups = $input->option('group');The result is:
[
'unit',
'integration',
]$verbose = $input->booleanOption(
'verbose',
false
);Recognized true values:
1
true
yes
on
Recognized false values:
0
false
no
off
$environment = $input->stringOption(
'environment',
'development'
);$port = $input->integerOption(
'port',
8000
);An invalid integer value throws ConsoleException.
$console->command(
name: 'cache:clear',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
$output->success('Cache cleared.');
return 0;
},
description: 'Remove all cached values.',
aliases: [
'cache:flush',
'cc',
]
);All of these execute the same command:
php console cache:clear
php console cache:flush
php console ccCommand names and aliases must be unique across the registry.
$console->command(
name: 'user:create',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
return 0;
},
description: 'Create an application user.',
usage: 'user:create <email> [--admin]'
);Display the command help:
php console help user:createOutput includes:
user:create
Description:
Create an application user.
Usage:
console user:create <email> [--admin]
Hidden commands
Hidden commands remain executable but are excluded from normal command listings.
$console->command(
name: 'internal:sync',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
$output->writeln(
'Internal synchronization complete.'
);
return 0;
},
hidden: true
);Commands may be created explicitly.
<?php
declare(strict_types=1);
use Ivi\Console\Command;
use Ivi\Console\Contracts\InputInterface;
use Ivi\Console\Contracts\OutputInterface;
$command = new Command(
name: 'status',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
$output->success(
'Application is running.'
);
return 0;
},
description: 'Display application status.',
aliases: [
'health',
],
usage: 'status',
hidden: false
);
$console->register($command);Create a command from another callable:
$command = Command::fromCallable(
name: 'queue:work',
handler: [$worker, 'run'],
description: 'Process queued jobs.'
);Applications may implement:
Ivi\Console\Contracts\CommandInterfaceExample:
<?php
declare(strict_types=1);
use Ivi\Console\Contracts\CommandInterface;
use Ivi\Console\Contracts\InputInterface;
use Ivi\Console\Contracts\OutputInterface;
final class AboutCommand implements CommandInterface
{
public function name(): string
{
return 'about';
}
public function description(): string
{
return 'Display application information.';
}
public function aliases(): array
{
return [];
}
public function usage(): string
{
return 'about';
}
public function isHidden(): bool
{
return false;
}
public function execute(
InputInterface $input,
OutputInterface $output
): int {
$output->writeln(
'Built with IviPHP.'
);
return 0;
}
}Register it:
$console->register(
new AboutCommand()
);$console->registerMany([
new AboutCommand(),
new StatusCommand(),
new CacheClearCommand(),
]);Replace commands with matching primary names:
$console->registerMany(
$commands,
replace: true
);Retrieve the registry:
$registry = $console->registry();Determine whether a command or alias exists:
if ($registry->has('cache:clear')) {
$command = $registry->get(
'cache:clear'
);
}Check only primary command names:
$exists = $registry->hasPrimary(
'cache:clear'
);Check aliases:
$isAlias = $registry->hasAlias('cc');Resolve an alias to its primary name:
$name = $registry->resolveName('cc');Result:
cache:clear
Return all commands:
$commands = $console->commands();Exclude hidden commands:
$commands = $console->commands(
includeHidden: false
);Return command names:
$names = $console
->registry()
->names();Return aliases:
$aliases = $console
->registry()
->aliases();Example:
[
'cache:flush' => 'cache:clear',
'cc' => 'cache:clear',
]$console->replace(
$updatedCommand
);The command must already be registered under the same primary name.
$console->forget('cache:clear');An alias may also be supplied:
$console->forget('cc');The command and all its aliases are removed.
When no command is supplied, the console displays the application name, version and visible commands.
php consoleThe same list is available through:
php console listThe built-in list behavior is used only when an application command named list is not registered.
Display all commands:
php console helpDisplay help for one command:
php console help cache:clearA command may also request its help page through an option:
php console cache:clear --helpor:
php console cache:clear -hThe built-in help behavior is used only when an application command named help is not registered.
php console --versionor:
php console -VExample output:
My Application 1.0.0
Render the version programmatically:
$console->renderVersion();$output->write('Loading...');Write with a newline:
$output->writeln('Complete.');Semantic output methods are also available:
$output->info(
'Reading configuration.'
);
$output->success(
'Application installed.'
);
$output->warning(
'Configuration file already exists.'
);
$output->error(
'Unable to connect to the database.'
);Regular messages are written to standard output.
Errors are written to standard error.
<?php
declare(strict_types=1);
use Ivi\Console\Output\ConsoleOutput;
$output = new ConsoleOutput();Disable ANSI decoration:
$output = new ConsoleOutput(
decorated: false
);Enable it explicitly:
$output = new ConsoleOutput(
decorated: true
);Change it later:
$output->setDecorated(false);Check the current setting:
if ($output->isDecorated()) {
echo 'ANSI decoration enabled.';
}$outputStream = fopen(
'php://memory',
'w+'
);
$errorStream = fopen(
'php://memory',
'w+'
);
$output = new ConsoleOutput(
outputStream: $outputStream,
errorStream: $errorStream,
decorated: false
);Externally supplied streams remain owned by the application.
Streams created internally by ConsoleOutput are closed automatically.
The concrete ConsoleOutput implementation provides a newline helper:
$output->newLine();Write several blank lines:
$output->newLine(2);$output->writeError(
'Raw error output.',
newline: true
);No semantic color is applied by writeError().
<?php
declare(strict_types=1);
use Ivi\Console\Input\ArgvInput;
$input = new ArgvInput([
'console',
'server:start',
'--host=127.0.0.1',
'--port=8080',
]);Retrieve parsed information:
$script = $input->script();
$command = $input->command();
$arguments = $input->arguments();
$options = $input->options();
$tokens = $input->tokens();$input = ArgvInput::fromTokens(
[
'cache:clear',
'--store=files',
],
script: 'ivi'
);$input = ArgvInput::fromGlobals();This reads PHP's global $argv value.
<?php
declare(strict_types=1);
use Ivi\Console\Input\ArgvInput;
use Ivi\Console\Output\ConsoleOutput;
$input = ArgvInput::fromTokens([
'hello',
'Gaspard',
]);
$output = new ConsoleOutput();
$exitCode = $console->run(
$input,
$output
);A minimal executable file may look like this:
#!/usr/bin/env php
<?php
declare(strict_types=1);
require dirname(__DIR__)
. '/vendor/autoload.php';
use Ivi\Console\Console;
use Ivi\Console\ConsoleManager;
use Ivi\Console\Contracts\InputInterface;
use Ivi\Console\Contracts\OutputInterface;
$console = new Console(
new ConsoleManager(
applicationName: 'Ivi Application',
applicationVersion: '1.0.0'
)
);
$console->command(
name: 'hello',
handler: static function (
InputInterface $input,
OutputInterface $output
): int {
$name = $input->argument(
0,
'Developer'
);
$output->success(
"Hello, {$name}."
);
return 0;
},
description: 'Display a greeting.',
usage: 'hello [name]'
);
exit($console->run());Make it executable:
chmod +x bin/consoleRun it:
./bin/console hello GaspardConsoleManager catches command exceptions by default.
$manager = new ConsoleManager(
catchExceptions: true
);When a command fails, the manager writes the exception message and returns exit code 1.
Disable automatic exception catching:
$console->setCatchExceptions(false);Exceptions are then propagated to the calling application.
Check the current configuration:
if ($console->catchesExceptions()) {
echo 'Exceptions are handled by the console.';
}Detailed exception output is disabled by default.
Enable it:
$console->setDebug(true);Debug output includes:
- exception class;
- source file;
- source line;
- stack trace;
- previous exception chain.
Check the current mode:
if ($console->isDebug()) {
echo 'Console debug mode enabled.';
}Detailed exception output should not normally be enabled in production environments.
When an unknown command is executed, the manager searches for similar registered commands.
php console cach:clearThe console may suggest:
Did you mean this command?
cache:clear
Retrieve suggestions programmatically:
$suggestions = $console->suggestCommands(
'cach:clear'
);Limit the number of suggestions:
$suggestions = $console->suggestCommands(
'cach:clear',
maximumSuggestions: 3
);Applications may implement:
Ivi\Console\Contracts\InputInterfaceRequired methods:
public function script(): string;
public function command(): ?string;
public function arguments(): array;
public function hasArgument(int $index): bool;
public function argument(
int $index,
mixed $default = null
): mixed;
public function options(): array;
public function hasOption(string $name): bool;
public function option(
string $name,
mixed $default = null
): mixed;
public function tokens(): array;Applications may implement:
Ivi\Console\Contracts\OutputInterfaceRequired methods:
public function write(
string $message,
bool $newline = false
): void;
public function writeln(
string $message = ''
): void;
public function info(string $message): void;
public function success(string $message): void;
public function warning(string $message): void;
public function error(string $message): void;
public function isDecorated(): bool;
public function setDecorated(
bool $decorated
): void;Console-system failures are represented by:
Ivi\Console\Exceptions\ConsoleExceptionExamples include:
- invalid command names;
- duplicate command registration;
- unknown commands;
- invalid aliases;
- alias conflicts;
- invalid input;
- invalid argument indexes;
- invalid option names;
- command execution failures;
- invalid exit codes;
- unavailable streams;
- terminal write failures;
- invalid configuration.
<?php
declare(strict_types=1);
use Ivi\Console\Exceptions\ConsoleException;
try {
$command = $console->get(
'missing:command'
);
} catch (ConsoleException $exception) {
echo $exception->getMessage();
$context = $exception->context();
}Exception context intentionally excludes raw command arguments and option values.
Remove every registered command and alias:
$console->clear();Return the number of registered commands:
$count = $console->count();Determine whether the registry is empty:
if ($console->registry()->isEmpty()) {
echo 'No commands registered.';
}iviphp/console follows these principles:
- framework-independent command execution;
- explicit input and output contracts;
- predictable command and alias resolution;
- simple closure-backed commands;
- support for custom command classes;
- safe exception context;
- separate standard output and error streams;
- explicit process exit codes;
- optional terminal decoration;
- compatibility with application-specific CLI architectures.
Ivi Console is open-source software released under the MIT License.
Maintained by Gaspard Kirira and Softadastra.