Symfony Console 与输入处理
Symfony Console 组件提供了强大的命令行输入处理能力,以下是主要方式和最佳实践:

基本命令结构
// src/Command/YourCommand.php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class YourCommand extends Command
{
protected static $defaultName = 'app:your-command';
protected function configure(): void
{
$this
->setDescription('命令描述')
->setHelp('命令帮助信息');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 处理逻辑
return Command::SUCCESS;
}
}
输入参数定义
1 参数 (Arguments) - 位置参数
protected function configure(): void
{
$this
->addArgument('name', InputArgument::REQUIRED, '用户名称')
->addArgument('age', InputArgument::OPTIONAL, '用户年龄', 18)
->addArgument('tags', InputArgument::IS_ARRAY, '标签列表');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 获取参数值
$name = $input->getArgument('name'); // 必须参数
$age = $input->getArgument('age'); // 可选参数,默认18
$tags = $input->getArgument('tags'); // 数组参数
$output->writeln("Name: $name, Age: $age");
$output->writeln('Tags: ' . implode(', ', $tags));
return Command::SUCCESS;
}
使用示例:
php bin/console app:your-command John 25 tag1 tag2 tag3
2 选项 (Options) - 命名参数
protected function configure(): void
{
$this
->addOption('format', 'f', InputOption::VALUE_REQUIRED, '输出格式', 'json')
->addOption('verbose', 'v', InputOption::VALUE_NONE, '详细输出')
->addOption('config', 'c', InputOption::VALUE_OPTIONAL, '配置文件路径')
->addOption('exclude', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, '排除项');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$format = $input->getOption('format'); // 有值选项
$verbose = $input->getOption('verbose'); // 布尔选项
$config = $input->getOption('config'); // 可选值选项
$exclude = $input->getOption('exclude'); // 数组选项
if ($verbose) {
$output->writeln("Format: $format");
}
return Command::SUCCESS;
}
使用示例:
# 基本用法 php bin/console app:your-command --format=yaml -v # 可选值选项(可以没有值) php bin/console app:your-command --config php bin/console app:your-command --config=config.yml # 数组选项(多次使用) php bin/console app:your-command --exclude=foo --exclude=bar
输入验证
1 自定义验证
protected function execute(InputInterface $input, OutputInterface $output): int
{
$email = $input->getArgument('email');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$output->writeln('<error>无效的邮箱地址</error>');
return Command::FAILURE;
}
return Command::SUCCESS;
}
2 使用选择器验证
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Helper\QuestionHelper;
protected function interact(InputInterface $input, OutputInterface $output): void
{
$helper = $this->getHelper('question');
// 选择题
$question = new ChoiceQuestion(
'选择颜色:',
['red', 'blue', 'green'],
0
);
$question->setErrorMessage('无效选择 %s');
$color = $helper->ask($input, $output, $question);
// 自定义验证
$question = new Question('请输入年龄:', 18);
$question->setValidator(function ($answer) {
if (!is_numeric($answer) || $answer < 0 || $answer > 150) {
throw new \RuntimeException('年龄必须在0-150之间');
}
return (int) $answer;
});
$age = $helper->ask($input, $output, $question);
}
交互式输入
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Helper\QuestionHelper;
protected function execute(InputInterface $input, OutputInterface $output): int
{
$helper = $this->getHelper('question');
// 确认提示
$question = new ConfirmationQuestion('继续操作吗?(y/n) ', false);
if (!$helper->ask($input, $output, $question)) {
return Command::SUCCESS;
}
// 隐藏输入(密码等)
$question = new Question('请输入密码:');
$question->setHidden(true);
$question->setHiddenFallback(false); // 如果不支持隐藏则抛出异常
$password = $helper->ask($input, $output, $question);
// 自动补全
$question = new Question('请输入命令:');
$question->setAutocompleterValues(['list', 'help', 'debug']);
$command = $helper->ask($input, $output, $question);
return Command::SUCCESS;
}
高级输入处理
1 表格输入
use Symfony\Component\Console\Helper\Table;
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 从标准输入读取表格数据
$data = [];
while ($line = fgets(STDIN)) {
$data[] = json_decode(trim($line), true);
}
$table = new Table($output);
$table
->setHeaders(['ID', 'Name', 'Email'])
->setRows($data);
$table->render();
return Command::SUCCESS;
}
2 CSV文件输入
protected function execute(InputInterface $input, OutputInterface $output): int
{
$csvFile = $input->getArgument('csv-file');
if (!file_exists($csvFile)) {
$output->writeln('<error>文件不存在</error>');
return Command::FAILURE;
}
$handle = fopen($csvFile, 'r');
$headers = fgetcsv($handle);
while (($row = fgetcsv($handle)) !== false) {
$data = array_combine($headers, $row);
// 处理数据...
}
fclose($handle);
return Command::SUCCESS;
}
输入样式和格式化
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 格式化输出
$output->writeln('<info>成功信息</info>');
$output->writeln('<error>错误信息</error>');
$output->writeln('<comment>注释信息</comment>');
$output->writeln('<question>问题信息</question>');
// 进度条
$progressBar = new ProgressBar($output, 50);
$progressBar->start();
for ($i = 0; $i < 50; $i++) {
usleep(10000); // 模拟工作
$progressBar->advance();
}
$progressBar->finish();
return Command::SUCCESS;
}
完整的命令示例
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
class UserImportCommand extends Command
{
protected static $defaultName = 'app:user:import';
protected function configure(): void
{
$this
->setDescription('批量导入用户')
->setHelp('从CSV文件导入用户数据')
->addArgument('file', InputArgument::REQUIRED, 'CSV文件路径')
->addOption('dry-run', null, InputOption::VALUE_NONE, '试运行,不实际导入')
->addOption('format', 'f', InputOption::VALUE_REQUIRED, '输出格式', 'table')
->addOption('batch-size', null, InputOption::VALUE_REQUIRED, '批处理大小', 100);
}
protected function interact(InputInterface $input, OutputInterface $output): void
{
$io = new SymfonyStyle($input, $output);
if (!$input->getArgument('file')) {
$file = $io->ask('请输入CSV文件路径');
$input->setArgument('file', $file);
}
if (!$io->confirm('确认导入?', false)) {
throw new \RuntimeException('导入已取消');
}
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$file = $input->getArgument('file');
if (!file_exists($file)) {
$io->error("文件 $file 不存在");
return Command::FAILURE;
}
// 文件处理逻辑
$io->section('开始导入');
$io->progressStart(100);
for ($i = 0; $i < 100; $i++) {
usleep(10000);
$io->progressAdvance();
}
$io->progressFinish();
$io->success('导入完成');
return Command::SUCCESS;
}
}
最佳实践
- 参数验证:始终验证用户输入
- 错误处理:使用适当的返回值(
SUCCESS/FAILURE/INVALID) - 用户反馈:提供清晰的进度指示和结果反馈
- 交互提示:使用问答组件处理复杂输入
- 默认值:为可选参数提供合理的默认值
- 文档:提供详细的帮助文本和示例
Symfony Console 的输入处理非常灵活,可以根据项目需求选择合适的处理方式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播