joetjen/abstractcli

Abstract base class for command line parsing

Maintainers

Package info

github.com/joetjen/php-abstractcli

Homepage

Issues

pkg:composer/joetjen/abstractcli

Transparency log

Statistics

Installs: 799

Dependents: 0

Suggesters: 0

Stars: 1

0.1.0 2026-07-29 09:40 UTC

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 $this and throw CLIException immediately if the definition is invalid.
  • AbstractCLI::run(array $args) - the static entry point; instantiates your class, parses $args (pass $argv), and calls execute(). Any error - and even --help/--version - ends the process via exit() from inside run(), so only the success path returns normally.
  • Inside execute(): getOption($name, $default = null), getArgument($idx, $default = null) and is($name) read back what was parsed.
  • setVersion(), setSummary(), setFooter() customize --help/--version output.

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.