命令行工具 #
一、Console概述 #
1.1 Console组件 #
Symfony Console组件提供强大的命令行工具支持:
text
┌─────────────────────────────────────────────────────┐
│ Console功能 │
├─────────────────────────────────────────────────────┤
│ • 自定义命令 │
│ • 参数和选项 │
│ • 输入输出格式化 │
│ • 表格和进度条 │
│ • 命令测试 │
│ • 定时任务集成 │
└─────────────────────────────────────────────────────┘
1.2 内置命令 #
bash
# 查看所有命令
php bin/console list
# 常用命令
php bin/console cache:clear
php bin/console debug:router
php bin/console make:entity
php bin/console doctrine:migrations:migrate
二、创建命令 #
2.1 使用Maker创建 #
bash
php bin/console make:command SendEmailsCommand
# 输出
created: src/Command/SendEmailsCommand.php
2.2 命令定义 #
php
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
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\Style\SymfonyStyle;
#[AsCommand(
name: 'app:send-emails',
description: '发送邮件',
)]
class SendEmailsCommand extends Command
{
protected function configure(): void
{
$this
->addArgument('recipient', InputArgument::REQUIRED, '收件人邮箱')
->addArgument('subject', InputArgument::OPTIONAL, '邮件主题', 'No Subject')
->addOption('dry-run', 'd', InputOption::VALUE_NONE, '试运行,不实际发送')
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$recipient = $input->getArgument('recipient');
$subject = $input->getArgument('subject');
$dryRun = $input->getOption('dry-run');
$io->title('发送邮件');
if ($dryRun) {
$io->note('试运行模式');
}
$io->text([
"收件人: $recipient",
"主题: $subject",
]);
if (!$dryRun) {
// 实际发送邮件
$io->success('邮件发送成功');
}
return Command::SUCCESS;
}
}
三、参数和选项 #
3.1 参数类型 #
php
<?php
protected function configure(): void
{
$this
// 必需参数
->addArgument('name', InputArgument::REQUIRED, '用户名')
// 可选参数
->addArgument('email', InputArgument::OPTIONAL, '邮箱')
// 数组参数
->addArgument('tags', InputArgument::IS_ARRAY, '标签')
// 默认值
->addArgument('count', InputArgument::OPTIONAL, '数量', 10)
;
}
3.2 选项类型 #
php
<?php
protected function configure(): void
{
$this
// 无值选项
->addOption('verbose', 'v', InputOption::VALUE_NONE, '详细输出')
// 必需值选项
->addOption('format', 'f', InputOption::VALUE_REQUIRED, '输出格式', 'json')
// 可选值选项
->addOption('limit', 'l', InputOption::VALUE_OPTIONAL, '限制数量', 100)
// 数组选项
->addOption('exclude', 'e', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, '排除项')
// 否定选项
->addOption('no-cache', null, InputOption::VALUE_NEGATABLE, '禁用缓存')
;
}
3.3 获取输入 #
php
<?php
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 获取参数
$name = $input->getArgument('name');
$tags = $input->getArgument('tags');
// 获取选项
$verbose = $input->getOption('verbose');
$format = $input->getOption('format');
$exclude = $input->getOption('exclude');
return Command::SUCCESS;
}
四、输出格式化 #
4.1 SymfonyStyle #
php
<?php
use Symfony\Component\Console\Style\SymfonyStyle;
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
// 标题
$io->title('命令标题');
// 章节
$io->section('章节标题');
// 文本
$io->text('普通文本');
$io->text(['文本1', '文本2', '文本3']);
// 列表
$io->listing(['项目1', '项目2', '项目3']);
// 成功消息
$io->success('操作成功');
$io->success(['成功1', '成功2']);
// 错误消息
$io->error('操作失败');
// 警告消息
$io->warning('警告信息');
// 注意消息
$io->note('注意信息');
// 提示消息
$io->caution('谨慎操作');
// 定义列表
$io->definitionList(
'标题',
['键1' => '值1'],
['键2' => '值2']
);
return Command::SUCCESS;
}
4.2 表格输出 #
php
<?php
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->table(
['ID', '名称', '邮箱'],
[
[1, '张三', 'zhangsan@example.com'],
[2, '李四', 'lisi@example.com'],
[3, '王五', 'wangwu@example.com'],
]
);
return Command::SUCCESS;
}
4.3 进度条 #
php
<?php
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$items = range(1, 100);
$io->progressStart(count($items));
foreach ($items as $item) {
// 处理项目
usleep(10000);
$io->progressAdvance();
}
$io->progressFinish();
return Command::SUCCESS;
}
五、交互输入 #
5.1 询问输入 #
php
<?php
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
// 简单询问
$name = $io->ask('请输入您的姓名', '默认姓名');
// 密码询问
$password = $io->askHidden('请输入密码');
// 确认询问
if (!$io->confirm('确定要继续吗?', false)) {
return Command::FAILURE;
}
// 选择询问
$choice = $io->choice(
'请选择颜色',
['red', 'green', 'blue'],
'red'
);
// 多选询问
$selected = $io->choice(
'请选择多个选项',
['option1', 'option2', 'option3'],
'0,1'
);
return Command::SUCCESS;
}
六、服务注入 #
6.1 构造函数注入 #
php
<?php
namespace App\Command;
use App\Service\UserService;
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:user:report',
description: '生成用户报告',
)]
class UserReportCommand extends Command
{
public function __construct(
private UserService $userService
) {
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$users = $this->userService->getAllUsers();
// 生成报告
return Command::SUCCESS;
}
}
七、定时任务 #
7.1 创建定时任务命令 #
php
<?php
namespace App\Command;
use App\Service\CleanupService;
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:cleanup',
description: '清理过期数据',
)]
class CleanupCommand extends Command
{
public function __construct(
private CleanupService $cleanupService
) {
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->cleanupService->cleanupExpiredData();
return Command::SUCCESS;
}
}
7.2 配置Cron #
bash
# crontab -e
# 每天凌晨2点清理
0 2 * * * cd /var/www/project && php bin/console app:cleanup >> /var/log/cleanup.log 2>&1
# 每小时发送邮件
0 * * * * cd /var/www/project && php bin/console app:send-emails
# 每5分钟检查队列
*/5 * * * * cd /var/www/project && php bin/console app:queue:process
八、命令测试 #
8.1 测试命令 #
php
<?php
namespace App\Tests\Command;
use App\Command\SendEmailsCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;
class SendEmailsCommandTest extends KernelTestCase
{
public function testExecute(): void
{
$kernel = self::bootKernel();
$application = new Application($kernel);
$command = $application->find('app:send-emails');
$commandTester = new CommandTester($command);
$commandTester->execute([
'recipient' => 'test@example.com',
'subject' => 'Test Subject',
'--dry-run' => true,
]);
$commandTester->assertCommandIsSuccessful();
$output = $commandTester->getDisplay();
$this->assertStringContainsString('试运行模式', $output);
$this->assertStringContainsString('test@example.com', $output);
}
}
九、命令最佳实践 #
9.1 命名规范 #
text
命令命名规范:
├── 使用命名空间:app:, doctrine:, cache:
├── 使用动词开头:send:, create:, delete:
├── 使用连字符分隔:user:report, cache:clear
└── 示例:app:user:report, app:email:send
9.2 设计原则 #
text
命令设计原则:
├── 单一职责:每个命令只做一件事
├── 幂等性:多次执行结果相同
├── 可测试:易于编写测试
├── 详细输出:提供足够的执行信息
└── 错误处理:优雅处理异常情况
十、总结 #
本章学习了:
- Console组件概述
- 创建自定义命令
- 参数和选项
- 输出格式化
- 交互输入
- 服务注入
- 定时任务
- 命令测试
下一章将学习 API开发。
最后更新:2026-03-28