# php-cli-tools: the output helpers behind WP-CLI's terminal interface

> php-cli-tools is a small MIT licensed PHP library of command line output helpers, with prompt functions, progress indicators, table and tree renderers, and an argument parser, published by the WP-CLI project and usable on its own.

**wp-cli/php-cli-tools** — A collection of tools to help with PHP command line utilities

- Repository: https://github.com/wp-cli/php-cli-tools
- Stars: 680 · Forks: 117
- Language: PHP
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/wp-cli-php-cli-tools

## A helper library rather than a framework

php-cli-tools is described as a collection of tools to help with PHP command line utilities, and the README describes the contents as functions and classes to assist with command line development. That is a deliberately small scope. There is no application here, no plugin system, and no runtime to configure. What you get is a set of functions for printing, asking questions, showing progress, rendering tables and trees, and parsing arguments. The project lives under the wp-cli organisation, so the code that ships inside WP-CLI and the code that other people use in their own scripts come from the same place. The audience is PHP developers who need a terminal interface that behaves predictably, in particular people who want their scripts to look and feel like WP-CLI commands. The requirement is PHP 5.6 or newer, with mbstring listed as a suggested extension because it is used for calculating string widths, which is what makes the padded and aligned output line up.

## Printing and asking questions in one namespace

The function list is short enough to read in one pass, and it splits into two groups. The first group handles output: cli\out prints a message, cli\out_padded prints it padded to a calculated width, cli\err writes to the error stream, and cli\line prints a message with a trailing newline, with an empty default. The second group handles interaction: cli\input reads a line from the user, cli\prompt asks a question with an optional default and a marker character, cli\choose offers a set of choices from a default string such as yn with a default answer, and cli\menu presents a list of items with a default selection and a title. The use of a choice string like yn rather than an array is a small design decision with a real effect: cli\choose gives you a yes or no prompt without you writing the validation loop, and the default value of n means an empty answer declines. The choice helper takes a question, a choices string and a default answer, and the menu helper takes the items, an optional default and a title that defaults to Choose an Item. Everything lives under a cli namespace, so the library reads as a set of namespaced functions rather than a set of classes you instantiate.

## Progress indicators with configurable intervals

Three notification and progress classes cover the common cases of a long running command. cli\notify\Dots prints a message followed by an animated series of dots, with a default of three dots and a hundred millisecond interval. cli\notify\Spinner does the same with a spinner, also on a hundred millisecond interval. cli\progress\Bar is a progress bar that takes the message, the total, and an interval, again defaulting to a hundred milliseconds. The interval parameter on all three is the point worth noting, because it controls how often the terminal is written to. A hundred milliseconds is a reasonable default for a foreground command, but on a slow terminal connection or over a serial console, a faster interval produces visible flicker, and nothing in the documentation suggests a way to detect that. The examples directory has separate files for notifications and for progress, including one named for the step format, which suggests the bar supports more than a plain percentage.

## The table renderer changes shape when output is piped

cli\Table is the largest component, with a constructor taking optional headers and rows, setters for both, addRow, a sort method taking a column, a setRenderer method taking a cli\table\Renderer instance, and a display method that prints the result. The interesting behaviour is automatic. The README states that the display function detects whether output is piped and, if it is, renders a tab delimited table instead of the ASCII table used for visual display. That single decision removes an entire class of bug that plagues command line tools, where a pretty table ends up in a log file or gets piped into another command and becomes unreadable. You can override the detection by calling setRenderer with one of the concrete cli\table\Renderer classes. The examples directory lists table, table alignment and table wrapping examples, so column alignment and wrapping are the behaviours that vary between renderers.

## Trees and a simple rule based argument parser

cli\Tree handles hierarchical output, with a constructor, setData taking an array, setRenderer taking a cli\tree\Renderer, and both render and display methods. The separation of render from display mirrors the table class, which suggests the intent is the same in both cases: produce the output, then decide how to write it. The argument parser is the component with the clearest limits. The README says argument parsing uses a simple framework for taking a list of command line arguments, usually straight from $_SERVER['argv'], and parses the input against a set of defined rules. The pointer to examples/arguments.php is the only documentation of those rules, so the rule format has to be learned from an example file rather than from a specification. For a tool with a handful of flags and a positional argument that is fine, and for a tool with subcommands, mutually exclusive groups, environment variable fallbacks and typed values it is not.

## Installing the library and finding the usage examples

There is no installation section in the README, so there is no command to copy here, and that is not an oversight so much as the shape of the project: it is a library rather than an application, and it is consumed as a dependency. The repository root carries a composer.json, which is the Composer manifest for the package, alongside the lib/ directory that holds the code, so the practical route is to require the package in your own project and let Composer place it on your autoloader. The library namespace is cli, so once it is available your code calls functions such as cli\out and classes such as cli\Table. The README points to the examples/ directory for usage throughout, and that directory is the real documentation: separate files cover arguments, colors, common output, menu, notify, progress in two forms, table rendering with alignment and wrapping variants, and tree display. Reading examples/table.php and examples/arguments.php is the fastest way to see what the library expects from you, and the README names examples/arguments.php specifically for the argument rules. There is also a test.php at the repository root and a tests/ directory driven by a phpunit.xml.dist configuration, so the library is exercised by tests rather than only by the example scripts.

## What the repository says about its own gaps

The Todo section of the README is short and unusually candid: expand the README, and add doc blocks to the rest of the code. That tells you the documentation lives in the examples directory rather than in prose, and that the functions beyond the ones listed are not yet individually documented. The repository layout backs that up. There is a lib/ directory holding the code, an examples/ directory with files covering arguments, colors, common usage, menu, notify, output, progress, tables and trees, and a tests/ directory with a phpunit.xml.dist configuration and a phpstan.neon.dist for static analysis. A typos.toml file suggests the prose is checked for spelling in CI, and there is an AGENTS.md plus an .editorconfig and .actrc for contributor setup. The library is MIT licensed, which means you can take it into a closed source product without obligations beyond keeping the licence text.

## Maintenance and the pace of releases

The project is not archived and the last push was on 2026-10-15, so the tree is being worked on. The release history shows two versions published on the same day, v0.13.1 and v0.13.2, both on 2026-10-07, with v0.13.0 earlier on 2026-04-13. That pattern suggests releases are not on a fixed cadence, and the version numbering is still below 1.0, which is where the API could still move. The requirement of PHP 5.6 is the other number to hold on to. It is a generous floor that keeps the library usable on old hosts, but it also means the code is written against a language level from years ago, so you should not expect modern PHP features such as enums, readonly properties, or first class callable syntax in the implementation. For an internal tool dependency that is a reasonable trade, and for a long lived public package it is worth a second look at your own minimum PHP version.

## Conclusion

Adopt php-cli-tools if you are writing a PHP command line program that needs consistent output, prompts, progress feedback and tabular or tree rendering, and you want the same look as WP-CLI without pulling in the whole framework. Do not adopt it for a one-off script that prints a single line, since the dependency is not worth the setup, and do not assume it covers argument parsing for a complex CLI, because the parser is described as a simple rule based framework. Verify first that PHP 5.6 or newer is available to you, since that is the stated floor, and read examples/arguments.php before designing your command line contract.

## FAQ

### What PHP version does php-cli-tools require?

The README lists PHP 5.6 or newer as the requirement, and names mbstring as a suggested extension because it is used for calculating string widths.

### Does php-cli-tools output a different table format when the output is piped?

Yes. The display function detects whether output is piped and renders a tab delimited table instead of the ASCII table used for visual display, and you can override that by passing a concrete cli\table\Renderer to setRenderer.

### How do I parse command line arguments with php-cli-tools?

Argument parsing takes a list of arguments, usually straight from $_SERVER['argv'], and matches them against a set of defined rules. The rules are demonstrated in examples/arguments.php in the repository.

### What licence does php-cli-tools use?

The project is released under the MIT licence, so it can be used in commercial and closed source products provided the licence and copyright notice are kept.

## Sources

- [Issues](https://github.com/wp-cli/php-cli-tools/issues)
- [License: MIT](https://github.com/wp-cli/php-cli-tools/blob/main/LICENSE)
- [README](https://github.com/wp-cli/php-cli-tools/blob/main/README.md)
- [Releases](https://github.com/wp-cli/php-cli-tools/releases)
- [wp-cli/php-cli-tools on GitHub](https://github.com/wp-cli/php-cli-tools)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/wp-cli-php-cli-tools
