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

Questions

Output offers two ways to read input from the user: free-form ask() and the option-constrained question() built around the Question value object.

ask() — free-form input

$name = $output->ask('What is your name?');
  • The prompt is printed, then a line is read from the input stream.
  • The answer is run through the same type casting as command input, so "42" comes back as int(42), "yes" as true, and so on.
  • Passing false as the second argument rejects an empty answer and keeps asking until something is entered:
$value = $output->ask('This cannot be empty:', false);
  • Typing exit or quit terminates the application.

question() — constrained input

Question describes the prompt, the set of acceptable answers, whether it is optional, and a default. Configure it fluently, then hand it to Output::question():

useInitPHP\Console\Question;
$question = (newQuestion())
->setQuestion('Pick an environment:')
->setOptions(['dev', 'staging', 'prod'])
->optional()
->setDefault('dev');
$env = $output->question($question);

Behaviour when an answer is submitted:

  1. If it matches one of the options → the (cast) answer is returned.
  2. If it is exit / quit → the application terminates.
  3. If the question is optional → the default is returned (or the raw answer when no default is set).
  4. If the question is required and nothing matched → the user is asked again.

Acceptable-answer matching

hasOption() matches both the verbatim answer and its cast form, so string input lines up with boolean or numeric options:

$q = newQuestion(); // default options: [true, false]$q->hasOption('true'); // true ("true" casts to bool true)$q->hasOption('yes'); // true ("yes" casts to bool true)$q->hasOption('false'); // true$q->hasOption('maybe'); // false

For a yes/no prompt you can therefore rely on the defaults, or set explicit string options:

(newQuestion())
->setQuestion('Continue?')
->setOptions(['yes', 'no']);

Defaults

A default is distinct from "no default": Question tracks whether one was set rather than inferring it from the value, so null is a perfectly valid default.

$q = newQuestion();
$q->hasDefault(); // false$q->getDefault(); // Question::NO_DEFAULT (sentinel)$q->setDefault('home');
$q->hasDefault(); // true$q->getDefault(); // 'home'
(newQuestion())->setDefault(null)->hasDefault(); // true

Question::NO_DEFAULT is a public sentinel constant; prefer hasDefault() over comparing against it.

The Question API at a glance

MethodPurpose
setQuestion(string) / getQuestion()The prompt text (empty string when unset).
setOptions(array) / getOptions()Replace / read the acceptable answers.
addOption(string)Append a single acceptable answer.
hasOption(string)Whether an answer is acceptable (verbatim or cast).
optional() / notOptional() / isOptional()Toggle / read the optional flag.
setDefault(mixed) / getDefault() / hasDefault()Manage the default answer.

addOption() compatibility note. A legacy two-argument form addOption($label, $value) is still honoured: when a second argument is given it is the value that gets registered and the first acts only as a label. Prefer the single-argument form addOption($value) in new code.

A worked example

useInitPHP\Console\Question;
$confirm = (newQuestion())
->setQuestion('Delete all records? [yes/no]')
->setOptions(['yes', 'no'])
->notOptional();
if ($output->question($confirm) === 'yes') {
// ... destructive action ...$output->success('Done.');
} else {
$output->info('Cancelled.');
}

Testing prompts

Inject an input stream pre-seeded with the answers:

useInitPHP\Console\Output;
$stdin = fopen('php://memory', 'r+');
fwrite($stdin, "Ada\n");
rewind($stdin);
$output = newOutput(STDOUT, $stdin);
$output->ask('Name?'); // 'Ada'

See Testing Commands for a complete strategy, including how to exercise the exit/quit path without killing the test runner.

Where to go next

Clone this wiki locally