OutputInterface
OutputInterface предоставляет методы для вывода текста в консоль.
<?php
declare(strict_types=1);
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(name: 'app:output-demo')]
final class OutputDemoCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
// Basic output
$output->writeln('Regular line');
$output->write('Without newline... ');
$output->writeln('continuing');
// Formatted output with tags
$output->writeln('<info>Info message (green)</info>');
$output->writeln('<comment>Comment (yellow)</comment>');
$output->writeln('<question>Question (black on cyan)</question>');
$output->writeln('<error>Error message (white on red)</error>');
// Custom formatting
$output->writeln('<fg=red>Red text</>');
$output->writeln('<fg=blue;bg=white>Blue on white</>');
$output->writeln('<fg=green;options=bold>Bold green</>');
$output->writeln('<fg=cyan;options=underscore>Underlined cyan</>');
// Multiple lines at once
$output->writeln([
'Line 1',
'Line 2',
'Line 3',
]);
return Command::SUCCESS;
}
}
SymfonyStyle
SymfonyStyle -- рекомендуемый способ форматирования ввода-вывода. Предоставляет единообразный стиль для всех команд.
<?php
declare(strict_types=1);
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'app:style-demo')]
final class StyleDemoCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
$io = new SymfonyStyle($input, $output);
// Title and section
$io->title('Application Style Demo');
$io->section('Section 1: Messages');
// Message types
$io->success('Operation completed successfully!');
$io->error('Something went wrong.');
$io->warning('Be careful with this operation.');
$io->note('This is an informational note.');
$io->caution('This action cannot be undone!');
$io->info('Processing started...');
// Text output
$io->text('Simple text message');
$io->text([
'First paragraph',
'Second paragraph',
]);
// Listing
$io->listing([
'First item',
'Second item',
'Third item',
]);
// Definition list
$io->definitionList(
['Name' => 'John Doe'],
['Email' => '[email protected]'],
['Role' => 'Admin'],
);
// Horizontal table
$io->horizontalTable(
['Name', 'Email', 'Role'],
[
['John', '[email protected]', 'Admin'],
],
);
// New line
$io->newLine(2);
return Command::SUCCESS;
}
}
Интерактивный ввод через SymfonyStyle
<?php
declare(strict_types=1);
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'app:interactive')]
final class InteractiveCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
$io = new SymfonyStyle($input, $output);
// Simple question
$name = $io->ask('What is your name?', 'Anonymous');
// Hidden input (password)
$password = $io->askHidden('Enter password');
// Confirmation (yes/no)
$confirmed = $io->confirm('Do you want to continue?', true);
// Choice question
$color = $io->choice(
'Select your favorite color',
['Red', 'Green', 'Blue'],
'Blue', // default
);
// Multi-select choice
// (user can select multiple options by separating with comma)
if ($confirmed) {
$io->success("Hello, $name! Your color: $color");
}
return Command::SUCCESS;
}
}
Table Helper
<?php
declare(strict_types=1);
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(name: 'app:table-demo')]
final class TableDemoCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
// Basic table
$table = new Table($output);
$table
->setHeaders(['ID', 'Name', 'Email', 'Role'])
->setRows([
[1, 'Alice', '[email protected]', 'Admin'],
[2, 'Bob', '[email protected]', 'User'],
new TableSeparator(),
[3, 'Charlie', '[email protected]', 'Editor'],
]);
$table->setStyle('box'); // box, compact, borderless, box-double
$table->render();
// Table via SymfonyStyle
$io = new \Symfony\Component\Console\Style\SymfonyStyle($input, $output);
$io->table(
['Name', 'Status'],
[
['Service A', '<info>Running</info>'],
['Service B', '<error>Stopped</error>'],
['Service C', '<comment>Starting</comment>'],
],
);
// Table with cell spanning
$table2 = new Table($output);
$table2
->setHeaders(['Name', 'Status', 'Details'])
->setRows([
['Server 1', 'OK', 'All good'],
new TableSeparator(),
[new TableCell('Summary', ['colspan' => 3])],
]);
$table2->render();
return Command::SUCCESS;
}
}
ProgressBar
<?php
declare(strict_types=1);
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'app:progress-demo')]
final class ProgressDemoCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
$items = range(1, 100);
// Basic ProgressBar
$progressBar = new ProgressBar($output, count($items));
$progressBar->start();
foreach ($items as $item) {
// Process item...
usleep(20000); // simulate work
$progressBar->advance();
}
$progressBar->finish();
$output->writeln(''); // new line after progress bar
// Custom format
$progressBar2 = new ProgressBar($output, 50);
$progressBar2->setFormat(
' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%'
);
$progressBar2->start();
for ($i = 0; $i < 50; $i++) {
usleep(20000);
$progressBar2->advance();
}
$progressBar2->finish();
$output->writeln('');
// Via SymfonyStyle (simplest)
$io = new SymfonyStyle($input, $output);
$io->progressStart(count($items));
foreach ($items as $item) {
usleep(10000);
$io->progressAdvance();
}
$io->progressFinish();
// ProgressBar with message
$progressBar3 = new ProgressBar($output, 3);
$progressBar3->setFormat(' %current%/%max% -- %message%');
$progressBar3->setMessage('Starting...');
$progressBar3->start();
$progressBar3->setMessage('Processing users...');
$progressBar3->advance();
usleep(500000);
$progressBar3->setMessage('Processing orders...');
$progressBar3->advance();
usleep(500000);
$progressBar3->setMessage('Done!');
$progressBar3->finish();
$output->writeln('');
return Command::SUCCESS;
}
}
Предопределённые форматы ProgressBar
| Формат | Описание |
|---|---|
normal |
Без подробностей |
verbose |
С прошедшим временем |
very_verbose |
С прошедшим и оставшимся временем |
debug |
С памятью |
QuestionHelper
<?php
declare(strict_types=1);
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
#[AsCommand(name: 'app:question-demo')]
final class QuestionDemoCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
/** @var QuestionHelper $helper */
$helper = $this->getHelper('question');
// Simple question with default
$question = new Question('Enter your name: ', 'World');
$name = $helper->ask($input, $output, $question);
// Question with validation
$emailQuestion = new Question('Enter email: ');
$emailQuestion->setValidator(function (?string $answer): string {
if (empty($answer) || !str_contains($answer, '@')) {
throw new \RuntimeException('Please enter a valid email.');
}
return $answer;
});
$emailQuestion->setMaxAttempts(3); // Max 3 tries
$email = $helper->ask($input, $output, $emailQuestion);
// Hidden question (password)
$passwordQuestion = new Question('Enter password: ');
$passwordQuestion->setHidden(true);
$passwordQuestion->setHiddenFallback(false); // Don't fallback to visible
$password = $helper->ask($input, $output, $passwordQuestion);
// Confirmation question
$confirm = new ConfirmationQuestion(
'Continue? (y/N) ',
false, // default: no
);
$proceed = $helper->ask($input, $output, $confirm);
// Choice question
$choice = new ChoiceQuestion(
'Select database driver',
['MySQL', 'PostgreSQL', 'SQLite'],
1, // default: PostgreSQL
);
$choice->setErrorMessage('Invalid driver: %s');
$driver = $helper->ask($input, $output, $choice);
// Multi-select choice
$multiChoice = new ChoiceQuestion(
'Select features (comma-separated)',
['Auth', 'API', 'Admin', 'CLI'],
);
$multiChoice->setMultiselect(true);
$features = $helper->ask($input, $output, $multiChoice);
// Autocomplete
$countryQuestion = new Question('Enter country: ');
$countryQuestion->setAutocompleterValues([
'France', 'Germany', 'Italy', 'Spain', 'Ukraine',
]);
$country = $helper->ask($input, $output, $countryQuestion);
$output->writeln("Name: $name, Email: $email, Driver: $driver");
return Command::SUCCESS;
}
}
Форматирование в SymfonyStyle: сводка
| Метод | Внешний вид |
|---|---|
title() |
Заголовок с подчёркиванием |
section() |
Подзаголовок |
text() |
Обычный текст |
listing() |
Маркированный список |
table() |
Таблица |
success() |
Зелёный блок с галочкой |
error() |
Красный блок с крестом |
warning() |
Жёлтый блок |
note() |
Блок с заметкой |
caution() |
Блок с предупреждением |
ask() |
Вопрос |
askHidden() |
Скрытый ввод |
confirm() |
Да/Нет |
choice() |
Выбор из списка |
progressStart/Advance/Finish() |
ProgressBar |
Итоги
SymfonyStyle-- рекомендуемый объект для ввода-выводаTableподдерживает стили: box, compact, borderless, box-doubleProgressBarс форматами: normal, verbose, very_verbose, debugQuestionHelper-- низкоуровневые вопросы с валидацией и автодополнениемSymfonyStyleоборачивает QuestionHelper:ask(),confirm(),choice()