Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Customizing a Command

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

We have a new console command! But... it doesn't do much yet, aside from printing out a message. Let's make it fancier.

Scroll to the top. This is where we have the name of our command, and there's also a description... which shows up next to the command. Let me change ours to

A self-aware command that can do... only one thing.

... lines 1 - 12
... line 14
description: 'A self-aware command that can do... only one thing.',
class TalkToMeCommand extends Command
... lines 19 - 43

Configuring Arguments and Options

Our command is called app:talk-to-me because, when we run this, I want to make it possible to pass a name to the command - like Ryan - and then it'll reply with "Hey Ryan!". So, literally, we'll type bin/console app:talk-to-me ryan and it'll reply back.

When you want to pass a value to a command, that's known as an argument... and those are configured down in... the configure() method. There's already an argument called arg1... so let's change that to name.

This key is completely internal: you'll never see the word name when you're using this command. But we will use this key to read the argument value in a minute. We can also give the argument a description and, if you want, you can make it required. I'll keep it as optional.

The next thing we have are options. These are like arguments... except that they start with a -- when you use them. I want to have an optional flag where we can say --yell to make the command yell our name back.

In this case, the name of the option, yell, is important: we will use this name when passing the option at the command line to use it. The InputOption::VALUE_NONE means that our flag will just be --yell and not --yell= some value. If your option accepts a value, you would change this to VALUE_REQUIRED. Finally, give this a description.

... lines 1 - 16
class TalkToMeCommand extends Command
protected function configure(): void
->addArgument('name', InputArgument::OPTIONAL, 'Your name')
->addOption('yell', null, InputOption::VALUE_NONE, 'Shall I yell?')
... lines 26 - 43

Beautiful! We're not using this argument and option yet... but we can already re-run our command with a --help option:

php bin/console app:talk-to-me --help

And... awesome! We see the description up here... along with some details about how to use the argument and the --yell option.

Filling in execute()

When we call our command, very simply, Symfony will call execute()... which is where the fun starts. Inside, we can do whatever we want. It passes us two arguments: $input and $output. If you want to read some input - like the name argument or the yell option, use $input. And if you want to output something, use $output.

But in Symfony, we normally pop these two things into another object called SymfonyStyle. This is helper class makes reading and outputing easier... and fancier.

Ok: let's start by saying $name = $input->getArgument('name'). If we don't have a name, I'll default this to whoever you are. Below, read the option: $shouldYell = $input->getOption('yell'):

... lines 1 - 16
class TalkToMeCommand extends Command
... lines 19 - 26
protected function execute(InputInterface $input, OutputInterface $output): int
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name') ?: 'whoever you are';
$shouldYell = $input->getOption('yell');
... lines 32 - 40

Cool. Let's clear out this stuff down here and start our message: $message = sprintf('Hey %s!', $name). Then if we want to yell, you know what to do: $message = strtoupper($message). Below, use $io->success() and put the message there.

... lines 1 - 16
class TalkToMeCommand extends Command
... lines 19 - 26
protected function execute(InputInterface $input, OutputInterface $output): int
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name') ?: 'whoever you are';
$shouldYell = $input->getOption('yell');
$message = sprintf('Hey %s!', $name);
if ($shouldYell) {
$message = strtoupper($message);
return Command::SUCCESS;

This is one of the many helper methods on the SymfonyStyle class that help format your output. There's also $io->warning(), $io->note(), and several others.

Let's try it. Spin over and run:

php bin/console app:talk-to-me ryan

And... oh hello there! If we yell:

php bin/console app:talk-to-me ryan --yell

THAT WORKS TOO! We can even yell at 'whoever I am':

php bin/console app:talk-to-me --yell

Awesome! But let's get crazier... by autowiring a service and asking a question interactively on the command line. That's next... and it's the last chapter!

Leave a comment!

Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "knplabs/knp-time-bundle": "^1.18", // v1.19.0
        "symfony/asset": "6.1.*", // v6.1.0-RC1
        "symfony/console": "6.1.*", // v6.1.0-RC1
        "symfony/dotenv": "6.1.*", // v6.1.0-RC1
        "symfony/flex": "^2", // v2.1.8
        "symfony/framework-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/http-client": "6.1.*", // v6.1.0-RC1
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/runtime": "6.1.*", // v6.1.0-RC1
        "symfony/twig-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/ux-turbo": "^2.0", // v2.1.1
        "symfony/webpack-encore-bundle": "^1.13", // v1.14.1
        "symfony/yaml": "6.1.*", // v6.1.0-RC1
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.0
    "require-dev": {
        "symfony/debug-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/maker-bundle": "^1.41", // v1.42.0
        "symfony/stopwatch": "6.1.*", // v6.1.0-RC1
        "symfony/web-profiler-bundle": "6.1.*" // v6.1.0-RC1