Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Commands With Arguments and Options

Commands With Arguments and Options

~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

A hardwired command rarely suffices – this chapter makes our overdue-tasks command CONFIGURABLE: a project filter as an argument, a "count only" mode as an option.

Arguments vs. options: the difference

TypeProperties
ArgumentREQUIRED (unless a default is set), POSITIONAL – app:command value.
OptionALWAYS optional, referenced BY NAME, order-independent – app:command --option=value or --option as a plain on/off switch.

Adding an argument: project filter

src/Command/ListOverdueTasksCommand.php
use Symfony\Component\Console\Attribute\Argument;
use App\Repository\ProjectRepository;

// ... class attribute and constructor as in chapter 39, ProjectRepository additionally injected ...

protected function execute(
    InputInterface $input,
    OutputInterface $output,
    #[Argument(description: 'Optional project ID to filter by')]
    ?int $projectId = null,
): int {
    $io = new SymfonyStyle($input, $output);

    if ($projectId !== null) {
        $project = $this->projectRepository->find($projectId);
        if ($project === null) {
            $io->error(sprintf('Project with ID %d not found.', $projectId));

            return Command::FAILURE;
        }
    }

    // ... rest of the logic as in chapter 39 ...
}

The MODERN syntax (Symfony 7.1+): #[Argument] DIRECTLY on the method parameter, with standard PHP typing (?int for optional). Symfony handles parsing and type conversion AUTOMATICALLY – no manual $input->getArgument('project-id') plus (int) cast needed anymore, as the older syntax required.

Adding an option: count only

use Symfony\Component\Console\Attribute\Option;

protected function execute(
    InputInterface $input,
    OutputInterface $output,
    #[Argument(description: 'Optional project ID to filter by')]
    ?int $projectId = null,
    #[Option(description: 'Only output the count, no details')]
    bool $countOnly = false,
): int {
    // ...
    if ($countOnly) {
        $io->writeln((string) count($tasks));

        return Command::SUCCESS;
    }
    // ... normal output as before ...
}

Running the command with arguments/options

php bin/console app:list-overdue-tasks           # all projects
php bin/console app:list-overdue-tasks 3         # only project ID 3
php bin/console app:list-overdue-tasks --count-only
php bin/console app:list-overdue-tasks 3 --count-only

Interactive prompts for missing required input

if ($io->confirm('Really mark all overdue tasks as done?', false)) {
    // ... update tasks ...
}

$answer = $io->ask('New status for all found tasks', 'in_progress');

confirm() asks a yes/no confirmation (with a default value as the second argument), ask() asks for free text – both pause execution until the user answers in the terminal. USEFUL for interactive use, but problematic for AUTOMATED scripts.

Achtung: Interactive prompts BLOCK indefinitely in automated contexts (cron jobs, CI/CD, chapter 41), since NOBODY can answer – Symfony offers the --no-interaction flag (also -n) for this, which automatically answers ALL interactive prompts with their default value. Commands meant to also run automated MUST work with --no-interaction.

Showing help for a command

php bin/console app:list-overdue-tasks --help

Tipp: --help shows AUTOMATICALLY generated documentation for ALL arguments and options, including the description texts from the attributes – another reason to always word THESE meaningfully instead of leaving them empty.