Console Input (Arguments & Options)

Console Input (Arguments & Options)

The most interesting part of the commands are the arguments and options that you can make available. These arguments and options allow you to pass dynamic information from the terminal to the command.

Using Command Arguments

Arguments are the strings - separated by spaces - that come after the command name itself. They are ordered, and can be optional or required. For example, to add an optional last_name argument to the command and make the name argument required:

  1. // ...
  2. use Symfony\Component\Console\Command\Command;
  3. use Symfony\Component\Console\Input\InputArgument;
  4. class GreetCommand extends Command
  5. {
  6. // ...
  7. protected function configure(): void
  8. {
  9. $this
  10. // ...
  11. ->addArgument('name', InputArgument::REQUIRED, 'Who do you want to greet?')
  12. ->addArgument('last_name', InputArgument::OPTIONAL, 'Your last name?')
  13. ;
  14. }
  15. }

You now have access to a last_name argument in your command:

  1. // ...
  2. use Symfony\Component\Console\Command\Command;
  3. use Symfony\Component\Console\Input\InputInterface;
  4. use Symfony\Component\Console\Output\OutputInterface;
  5. class GreetCommand extends Command
  6. {
  7. // ...
  8. protected function execute(InputInterface $input, OutputInterface $output): int
  9. {
  10. $text = 'Hi '.$input->getArgument('name');
  11. $lastName = $input->getArgument('last_name');
  12. if ($lastName) {
  13. $text .= ' '.$lastName;
  14. }
  15. $output->writeln($text.'!');
  16. return 0;
  17. }
  18. }

The command can now be used in either of the following ways:

  1. $ php bin/console app:greet Fabien
  2. Hi Fabien!
  3. $ php bin/console app:greet Fabien Potencier
  4. Hi Fabien Potencier!

It is also possible to let an argument take a list of values (imagine you want to greet all your friends). Only the last argument can be a list:

  1. $this
  2. // ...
  3. ->addArgument(
  4. 'names',
  5. InputArgument::IS_ARRAY,
  6. 'Who do you want to greet (separate multiple names with a space)?'
  7. )
  8. ;

To use this, specify as many names as you want:

  1. $ php bin/console app:greet Fabien Ryan Bernhard

You can access the names argument as an array:

  1. $names = $input->getArgument('names');
  2. if (count($names) > 0) {
  3. $text .= ' '.implode(', ', $names);
  4. }

There are three argument variants you can use:

InputArgument::REQUIRED

The argument is mandatory. The command doesn’t run if the argument isn’t provided;

InputArgument::OPTIONAL

The argument is optional and therefore can be omitted. This is the default behavior of arguments;

InputArgument::IS_ARRAY

The argument can contain any number of values. For that reason, it must be used at the end of the argument list.

You can combine IS_ARRAY with REQUIRED or OPTIONAL like this:

  1. $this
  2. // ...
  3. ->addArgument(
  4. 'names',
  5. InputArgument::IS_ARRAY | InputArgument::REQUIRED,
  6. 'Who do you want to greet (separate multiple names with a space)?'
  7. )
  8. ;

Using Command Options

Unlike arguments, options are not ordered (meaning you can specify them in any order) and are specified with two dashes (e.g. --yell). Options are always optional, and can be setup to accept a value (e.g. --dir=src) or as a boolean flag without a value (e.g. --yell).

For example, add a new option to the command that can be used to specify how many times in a row the message should be printed:

  1. // ...
  2. use Symfony\Component\Console\Input\InputOption;
  3. $this
  4. // ...
  5. ->addOption(
  6. 'iterations',
  7. null,
  8. InputOption::VALUE_REQUIRED,
  9. 'How many times should the message be printed?',
  10. 1
  11. )
  12. ;

Next, use this in the command to print the message multiple times:

  1. for ($i = 0; $i < $input->getOption('iterations'); $i++) {
  2. $output->writeln($text);
  3. }

Now, when you run the command, you can optionally specify a --iterations flag:

  1. # no --iterations provided, the default (1) is used
  2. $ php bin/console app:greet Fabien
  3. Hi Fabien!
  4. $ php bin/console app:greet Fabien --iterations=5
  5. Hi Fabien!
  6. Hi Fabien!
  7. Hi Fabien!
  8. Hi Fabien!
  9. Hi Fabien!
  10. # the order of options isn't important
  11. $ php bin/console app:greet Fabien --iterations=5 --yell
  12. $ php bin/console app:greet Fabien --yell --iterations=5
  13. $ php bin/console app:greet --yell --iterations=5 Fabien

Tip

You can also declare a one-letter shortcut that you can call with a single dash, like -i:

  1. $this
  2. // ...
  3. ->addOption(
  4. 'iterations',
  5. 'i',
  6. InputOption::VALUE_REQUIRED,
  7. 'How many times should the message be printed?',
  8. 1
  9. )
  10. ;

Note that to comply with the docopt standard, long options can specify their values after a whitespace or an = sign (e.g. --iterations 5 or --iterations=5), but short options can only use whitespaces or no separation at all (e.g. -i 5 or -i5).

Caution

While it is possible to separate an option from its value with a whitespace, using this form leads to an ambiguity should the option appear before the command name. For example, php bin/console --iterations 5 app:greet Fabien is ambiguous; Symfony would interpret 5 as the command name. To avoid this situation, always place options after the command name, or avoid using a space to separate the option name from its value.

There are four option variants you can use:

InputOption::VALUE_IS_ARRAY

This option accepts multiple values (e.g. --dir=/foo --dir=/bar);

InputOption::VALUE_NONE

Do not accept input for this option (e.g. --yell). The value returned from is a boolean (false if the option is not provided). This is the default behavior of options;

InputOption::VALUE_REQUIRED

This value is required (e.g. --iterations=5 or -i5), the option itself is still optional;

InputOption::VALUE_OPTIONAL

This option may or may not have a value (e.g. --yell or --yell=loud).

You can combine VALUE_IS_ARRAY with VALUE_REQUIRED or VALUE_OPTIONAL like this:

  1. $this
  2. // ...
  3. ->addOption(
  4. 'colors',
  5. null,
  6. InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
  7. 'Which colors do you like?',
  8. ['blue', 'red']
  9. )
  10. ;

Options with optional arguments

There is nothing forbidding you to create a command with an option that optionally accepts a value, but it’s a bit tricky. Consider this example:

  1. // ...
  2. use Symfony\Component\Console\Input\InputOption;
  3. $this
  4. // ...
  5. ->addOption(
  6. 'yell',
  7. null,
  8. InputOption::VALUE_OPTIONAL,
  9. 'Should I yell while greeting?'
  10. )
  11. ;

This option can be used in 3 ways: greet --yell, greet --yell=louder, and greet. However, it’s hard to distinguish between passing the option without a value (greet --yell) and not passing the option (greet).

To solve this issue, you have to set the option’s default value to false:

  1. // ...
  2. use Symfony\Component\Console\Input\InputOption;
  3. $this
  4. // ...
  5. ->addOption(
  6. 'yell',
  7. null,
  8. InputOption::VALUE_OPTIONAL,
  9. 'Should I yell while greeting?',
  10. false // this is the new default value, instead of null
  11. )
  12. ;

Now it’s possible to differentiate between not passing the option and not passing any value for it:

  1. $optionValue = $input->getOption('yell');
  2. if (false === $optionValue) {
  3. // in this case, the option was not passed when running the command
  4. $yell = false;
  5. $yellLouder = false;
  6. } elseif (null === $optionValue) {
  7. // in this case, the option was passed when running the command
  8. // but no value was given to it
  9. $yell = true;
  10. $yellLouder = false;
  11. } else {
  12. // in this case, the option was passed when running the command and
  13. // some specific value was given to it
  14. $yell = true;
  15. if ('louder' === $optionValue) {
  16. $yellLouder = true;
  17. } else {
  18. $yellLouder = false;
  19. }
  20. }

The above code can be simplified as follows because false !== null:

  1. $optionValue = $input->getOption('yell');
  2. $yell = ($optionValue !== false);
  3. $yellLouder = ($optionValue === 'louder');

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.