iviphp / console
Console commands, input parsing and terminal output for the IviPHP ecosystem.
Requires
- php: >=8.2
- iviphp/contracts: ^0.1
- iviphp/support: ^0.1
This package is not auto-updated.
Last update: 2026-07-21 23:13:44 UTC
README
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.
Requirements
- PHP 8.2 or later
iviphp/contractsiviphp/support
Installation
composer require iviphp/console
Features
- 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
Core concepts
Console manager
ConsoleManager coordinates:
- command registration;
- command resolution;
- input parsing;
- terminal output;
- command execution;
- help pages;
- command listings;
- version output;
- exception handling;
- process exit codes.
Console API
Console is the public application-facing wrapper around ConsoleManager.
Command
A command defines:
- a unique name;
- a description;
- optional aliases;
- a usage expression;
- whether it is hidden;
- execution logic.
Input
ArgvInput parses an argv-compatible array into:
- executable script;
- command name;
- positional arguments;
- named options;
- original tokens.
Output
ConsoleOutput writes regular messages to standard output and errors to standard error.
ANSI terminal decoration can be detected automatically or configured explicitly.
Creating a console application
<?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);
Creating a command
<?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 hello
Output:
Hello from IviPHP.
Command exit codes
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.
Positional arguments
$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 Gaspard
Output:
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.
Long options
The parser supports boolean long options:
php console build --verbose
Retrieve 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 production
Disabled boolean options
Options prefixed with --no- are stored as false.
php console build --no-cache
Retrieve the normalized option name:
$cacheEnabled = $input->booleanOption( 'cache', true );
The value is false.
Short options
Single short options are supported:
php console build -v
$verbose = $input->hasOption('v');
Combined short flags are also supported:
php console build -abc
This 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 );
Stopping option parsing
The special -- token stops option parsing.
Every following token becomes a positional argument.
php console inspect -- --example --verbose
The command receives:
[
'--example',
'--verbose',
]
as positional arguments.
Repeated options
Repeated options are stored as arrays.
php console test --group=unit --group=integration
$groups = $input->option('group');
The result is:
[
'unit',
'integration',
]
Typed option helpers
Boolean options
$verbose = $input->booleanOption( 'verbose', false );
Recognized true values:
1
true
yes
on
Recognized false values:
0
false
no
off
String options
$environment = $input->stringOption( 'environment', 'development' );
Integer options
$port = $input->integerOption( 'port', 8000 );
An invalid integer value throws ConsoleException.
Command aliases
$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 cc
Command names and aliases must be unique across the registry.
Usage expressions
$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:create
Output 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 );
Registering command objects
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.' );
Custom command classes
Applications may implement:
Ivi\Console\Contracts\CommandInterface
Example:
<?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() );
Registering multiple commands
$console->registerMany([ new AboutCommand(), new StatusCommand(), new CacheClearCommand(), ]);
Replace commands with matching primary names:
$console->registerMany( $commands, replace: true );
Command registry
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
Listing commands
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',
]
Replacing a command
$console->replace( $updatedCommand );
The command must already be registered under the same primary name.
Removing commands
$console->forget('cache:clear');
An alias may also be supplied:
$console->forget('cc');
The command and all its aliases are removed.
Built-in command list
When no command is supplied, the console displays the application name, version and visible commands.
php console
The same list is available through:
php console list
The built-in list behavior is used only when an application command named list is not registered.
Built-in help
Display all commands:
php console help
Display help for one command:
php console help cache:clear
A command may also request its help page through an option:
php console cache:clear --help
or:
php console cache:clear -h
The built-in help behavior is used only when an application command named help is not registered.
Version output
php console --version
or:
php console -V
Example output:
My Application 1.0.0
Render the version programmatically:
$console->renderVersion();
Terminal output
$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.
Creating console output
<?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.'; }
Custom output streams
$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.
Blank lines
The concrete ConsoleOutput implementation provides a newline helper:
$output->newLine();
Write several blank lines:
$output->newLine(2);
Writing directly to standard error
$output->writeError( 'Raw error output.', newline: true );
No semantic color is applied by writeError().
Creating input manually
<?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();
Creating input without a script token
$input = ArgvInput::fromTokens( [ 'cache:clear', '--store=files', ], script: 'ivi' );
Reading global argv
$input = ArgvInput::fromGlobals();
This reads PHP's global $argv value.
Executing custom input
<?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 );
Running the console application
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/console
Run it:
./bin/console hello Gaspard
Exception handling
ConsoleManager 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.'; }
Debug exception output
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.
Unknown command suggestions
When an unknown command is executed, the manager searches for similar registered commands.
php console cach:clear
The 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 );
Custom input implementations
Applications may implement:
Ivi\Console\Contracts\InputInterface
Required 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;
Custom output implementations
Applications may implement:
Ivi\Console\Contracts\OutputInterface
Required 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;
Exceptions
Console-system failures are represented by:
Ivi\Console\Exceptions\ConsoleException
Examples 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.
Clearing the registry
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.'; }
Design principles
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.
License
Ivi Console is open-source software released under the MIT License.
Maintainer
Maintained by Gaspard Kirira and Softadastra.