joetjen / abstractcli
Abstract base class for command line parsing
Requires
- php: ^7.4 || ^8.0
Requires (Dev)
- phpunit/phpunit: ^9.6 || ^10.5 || ^11.0
This package is auto-updated.
Last update: 2026-08-03 13:15:42 UTC
README
A small, dependency-free abstract base class for building command line PHP scripts: define your
options and arguments declaratively, and AbstractCLI takes care of parsing $argv, validating
input, and printing --help/--version output for you.
It ships with three built-in options out of the box:
-h,--help- print usage and exit-v,--verbose- a boolean switch, off by default-V,--version- print the program name/version and exit
Documentation
This README covers requirements, installation and a complete quick-start example. For everything else:
- QUICKSTART.md - the fastest path to a working script.
- TUTORIAL.md - a guided, step-by-step walkthrough that builds up a realistic command feature by feature, verifying its output at every step.
- CHEATSHEET.md - a condensed reference for the full API, plus a table of behaviors that are easy to get wrong.
- EXAMPLES.md - short, standalone, copy-pasteable scripts for common cases.
- CHANGELOG.md - notable changes, release by release.
- CONTRIBUTION.md - how to set up a dev environment, run the tests, and what a good pull request looks like.
- LICENSE - MIT.
Requirements
- PHP 7.4 or 8.0+ (tested against PHP 8.4)
Installation
composer require joetjen/abstractcli
Quick start
<?php require __DIR__ . '/vendor/autoload.php'; use JOetjen\AbstractCLI\AbstractCLI; use JOetjen\AbstractCLI\CLIException; class GreetCli extends AbstractCLI { public function __construct() { parent::__construct(); $this->setVersion('1.0.0'); $this->setSummary('Greets someone, optionally more than once.'); $this->setFooter('Example: greet --shout --times 3 World'); $this->addOption(array( 'short' => 's', 'long' => 'shout', 'type' => self::TYPE__SWITCH, 'desc' => 'Print the greeting in capital letters.', )); $this->addOption(array( 'short' => 't', 'long' => 'times', 'type' => self::TYPE__OPTIONAL, 'name' => 'times', 'desc' => 'How many times to greet (default: 1).', 'check' => 'checkTimes', )); $this->addArgument(array( 'name' => 'NAME', 'type' => self::TYPE__MANDATORY, )); } public function checkTimes($value) { if (!ctype_digit((string) $value)) { throw new CLIException('"%s" is not a valid number of times!', $value); } } protected function execute() { $name = $this->getArgument(0); // the first argument defined, i.e. NAME $times = (int) $this->getOption('times', 1); $message = sprintf('Hello, %s!', $name); if ($this->is('shout')) { $message = strtoupper($message); } for ($i = 0; $i < $times; $i++) { echo $message, PHP_EOL; } return 0; } } exit((int) GreetCli::run($argv));
$ php greet.php --shout --times 2 World
HELLO, WORLD!
HELLO, WORLD!
$ php greet.php --help
USAGE: greet.php [OPTIONS...] NAME
Greets someone, optionally more than once.
OPTIONS:
-h, --help This help text.
-s, --shout Print the greeting in capital letters.
-t, --times [TIMES] How many times to greet (default: 1).
-v, --verbose Make the script more talkative!
-V, --version Show version and quit.
Example: greet --shout --times 3 World
For a step-by-step explanation of how this example was built up, see TUTORIAL.md.
API at a glance
addOption(array $params)/addArgument(array $params)- declare options/arguments in your constructor. Both return$thisand throwCLIExceptionimmediately if the definition is invalid.AbstractCLI::run(array $args)- the static entry point; instantiates your class, parses$args(pass$argv), and callsexecute(). Any error - and even--help/--version- ends the process viaexit()from insiderun(), so only the success path returns normally.- Inside
execute():getOption($name, $default = null),getArgument($idx, $default = null)andis($name)read back what was parsed. setVersion(),setSummary(),setFooter()customize--help/--versionoutput.
The full reference, including the exact rules for option types and a few genuinely surprising
edge cases (an "..." argument that doesn't collect an array; a TYPE__MANDATORY option that
isn't actually required to be present), is in
CHEATSHEET.md.
Development
composer install composer test # run the test suite composer test-coverage # run the test suite with a text coverage report (requires Xdebug or PCOV)
The test suite (tests/) covers option/argument configuration and validation, the parser
(including the edge cases mentioned above), help/usage/version output formatting, and full
end-to-end run() behavior (exit codes included) via real child PHP processes. See
CONTRIBUTION.md for
more.
License
Released under the MIT License.