Skip to content
Muhammet Şafak edited this page May 29, 2026 · 1 revision

FAQ

Quick answers to questions that come up when using the package. If yours is not here, please open an issue — documentation fixes are reviewed eagerly.

General

What is initphp/console for?

Writing small-to-medium command-line tools in PHP: routing a command name to a handler, parsing its arguments, printing coloured output, asking questions, and rendering tables. It is dependency-free and deliberately minimal.

What is it NOT for?

  • Deep sub-command trees, shell auto-completion, or a rich argument grammar (variadics, negatable flags, -- passthrough). The parser is flat — see Input.
  • A built-in DI/service layer. Compose dependencies yourself; the package only routes the invocation.
  • Output verbosity levels / structured logging out of the box. Build them on top of Output.

Does it have any runtime dependencies?

No. Dev tools (PHPUnit, PHPStan, PHP_CodeSniffer) live under require-dev. The runtime requires PHP only; ext-mbstring is an optional enhancement for table alignment.

Terminology

Why is --name an "argument" but -v an "option"?

That is this library's convention: --long tokens are arguments, -short tokens are options, and bare tokens are segments. It is the opposite of some other frameworks, so double-check when porting code. See Input.

Usage

How do I read a value that may be --name or -name?

Declare an InputArgument: its run() looks the value up as an argument first, then as an option, under the same name. For ad-hoc reads, check both with getArgument() / getOption().

Why did --age=30 come back as an int, not a string?

All tokens are cast by Helpers::strValueCast(): integer-like → int, decimal-like → float, true/false/yes/nobool, nullnull. Pass it through (string) if you need the text form, or declare the argument as InputArgument::STR to have it stringified.

How do I give a command a default for a missing argument?

Two ways: read with a default — $input->getArgument('name', 'World') — or declare an optional InputArgument with a default value, which the framework writes back before execute() runs.

How do I abort a command with an error message?

throw from the handler. The dispatcher catches any Throwable, prints [ERROR] <message>, and run() returns false. You do not need to call exit() yourself. See Exceptions.

How do I set the process exit code?

run() returns a bool. Map it in your entry script:

exit($console->run() ? 0 : 1);

Why does typing exit at a prompt kill my program?

ask() and question() treat exit and quit as a request to terminate — they call the protected Output::terminate(), which exits by default. To intercept it (cleanup, or testing), subclass Output and override terminate(). See Testing Commands.

My yes/no question rejects "yes". Why?

question() accepts an answer only if it is in the question's options. The default options are [true, false], and hasOption() matches the cast form — so "yes"/"no"/"true"/"false" all work against the defaults. If you set custom string options (setOptions(['y', 'n'])), the answer must match one of those. See Questions.

Can I register a command as an object method or invokable?

Yes. The handler is any PHP callable: a closure, 'Class::method', [$object, 'method'], or an invokable object. Class-based commands use the Command base class and are registered by class name.

Output & tables

How do I capture output for a test?

Inject a php://memory stream: new Output($stream), then read the stream after running. See Output → injecting streams and Testing Commands.

Why do my table booleans show as [TRUE]/[FALSE]?

That is how non-string values are stringified. Convert to 'yes'/'no' (or any string) before calling row() if you want different text. See Tables → how values are rendered.

My UTF-8 table columns are misaligned.

Install ext-mbstring. Widths are measured with mb_strlen() when available; without it the renderer falls back to byte length. See Tables → multibyte.

PHP / tooling

Which PHP versions are supported?

PHP 7.2 and up. CI runs the QA matrix on 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, and 8.4.

Why does the code use PHPDoc types instead of native types in places?

To stay compatible with PHP 7.2, which lacks typed properties (7.4) and union types (8.0). Nullable hints (?Type) and scalar parameter/return types are used natively where 7.2 allows. See the note atop the API Reference.

What is the PHPStan level?

Level 6, and the source is clean at that level. Coding standard is PSR-12 (checked with PHP_CodeSniffer).

Where are the tests?

Under tests/ in the source repository. They cover input parsing, argument validation, output formatting, the question flow, the dispatcher, and the table renderer — using injected in-memory streams (see Testing Commands).

Versioning

Is the table renderer the same as initphp/cli-table?

Yes — it was merged in as of 2.1 and the old class name still resolves via a class_alias. See the Migration Guide.

Will 2.x see breaking changes?

Not within the 2.x line. Anything that breaks the public contract (classes, interfaces, the Command hooks, exception behaviour) would require a major bump. New optional parameters and new methods are added compatibly.

Other

Where do I report a security issue?

See SECURITY.md in the InitPHP org profile. Please do not file public issues for vulnerabilities.

Where do I open feature requests or discussions?

InitPHP Discussions is the place for open-ended threads; concrete bug reports and proposals belong in the issue tracker.

Clone this wiki locally