symfony/console
Symfony Console makes it easy to build beautiful, testable command-line applications in PHP. It provides structured commands, arguments and options, interactive prompts, styled output, helpers, and robust input/output handling for modern CLIs.
Installation:
composer require symfony/console
Laravel already includes this package as a dependency via Symfony components.
First Command:
Create a basic command in app/Console/Commands/ (e.g., TestCommand.php):
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class TestCommand extends Command
{
protected $signature = 'test:greet {name?}';
protected $description = 'Display a greeting';
public function handle()
{
$name = $this->argument('name') ?: 'World';
$this->info("Hello, {$name}!");
}
}
Register it in app/Console/Kernel.php:
protected $commands = [
Commands\TestCommand::class,
];
Run It:
php artisan test:greet Laravel
artisan is the CLI application).Symfony\Component\Console\Command\Command (base class for commands)Symfony\Component\Console\Application (manages commands)Symfony\Component\Console\Output\OutputInterface (output handling)Workflow:
$signature (e.g., {name?} for optional args, --force for flags).$description for help text.handle() for command logic. Use $this->argument()/$this->option() to access inputs.Example:
protected $signature = 'user:create {--admin} {name} {email}';
protected $description = 'Create a new user';
public function handle()
{
$name = $this->argument('name');
$email = $this->argument('email');
$isAdmin = $this->option('admin');
// Logic here...
}
Patterns:
$this->info('Success!');
$this->error('Failed!');
$this->line('Plain text');
$this->comment('Hint');
$this->text('<options=bold>Bold</>');
$this->text('<fg=green>Green</>');
$progressBar = $this->output->createProgressBar(100);
for ($i = 0; $i <= 100; $i++) {
$progressBar->advance();
}
$progressBar->finish();
Patterns:
validateArguments() or validateOptions():
protected function validateArguments()
{
if ($this->argument('name') === 'admin') {
throw new \InvalidArgumentException('Name cannot be "admin".');
}
}
$choice = $this->choice('Select environment', ['dev', 'staging', 'prod'], 'dev');
Patterns:
if ($this->confirm('Proceed?', false)) {
// ...
}
$name = $this->ask('Your name');
$secret = $this->secret('Password');
$password = $this->askHidden('Password');
Patterns:
Symfony\Component\Console\Tester\CommandTester:
use Symfony\Component\Console\Tester\CommandTester;
public function testCommand()
{
$command = new TestCommand();
$commandTester = new CommandTester($command);
$commandTester->execute(['name' => 'Laravel']);
$this->assertEquals('Hello, Laravel!', trim($commandTester->getDisplay()));
}
Artisan::call():
$exitCode = Artisan::call('test:greet', ['name' => 'Laravel']);
$this->assertEquals(0, $exitCode);
Patterns:
protected $group in Kernel.php to organize commands under namespaces:
protected $commands = [
'user' => [
Commands\UserCreateCommand::class,
Commands\UserListCommand::class,
],
];
Run with:
php artisan user:create
use Symfony\Component\Console\Style\SymfonyStyle;
public function handle()
{
$io = new SymfonyStyle($this->output, $this->input);
$io->title('My Command');
$io->section('Details');
$io->table(['Name', 'Email'], [['Laravel', 'laravel@example.com']]);
}
Patterns:
ConsoleEvents::COMMAND):
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
public function boot()
{
$this->commands['test:greet']->listen(function (ConsoleCommandEvent $event) {
if ($event->getInput()->hasParameterOption('--verbose')) {
$event->getCommand()->getApplication()->getHelperSet()->set(new VerboseHelper());
}
});
}
Output Buffering:
echo with Symfony’s output methods (e.g., $this->line()). Use $this->output->write() for raw output.$this->output->isDecorated() to check for ANSI support before styling.Signal Handling:
SIGINT (Ctrl+C). Use $this->input->isInteractive() to check for interactive mode.handleSignal() in custom commands for graceful shutdowns:
protected function handleSignal($signal, $previous)
{
$this->info('Shutting down...');
return parent::handleSignal($signal, $previous);
}
Progress Bars in Sections:
ConsoleSectionOutput. Use $this->output->section() sparingly with progress bars.$this->output->overwrite() carefully.Windows Line Endings:
\r\n line endings can break output formatting. Use $this->output->setDecorated(false) or normalize line endings:
$this->output->write(str_replace("\r\n", "\n", $text));
Argument Parsing:
# (e.g., --env=#) may cause issues. Use $this->input->getArgumentOptionValue() to access them:
$env = $this->input->getArgumentOptionValue('--env');
Testing Quirks:
ApplicationTester may ignore interactive/verbosity flags if SHELL_VERBOSITY is set. Mock the environment:
putenv('SHELL_VERBOSITY=1');
Enable Verbose Output:
php artisan command --verbose
Or in code:
$this->output->setVerbosity(self::VERBOSITY_VERBOSE);
Inspect Input/Output: Dump raw input/output:
$this->output->writeln('<comment>Input:</comment> ' . print_r($this->input->getArguments(), true));
Check for Hidden Commands:
Hidden commands (e.g., cache:clear) won’t appear in help. Use --all:
php artisan --all
Profile Commands: Enable profiling to debug performance:
php artisan command --profile
View results in var/profile/.
Symfony\Component\Console\Helper\HelperSet:
$helperSet = $this->getHelper
How can I help you explore Laravel packages today?