如何使用 Symfony Console 组件创建自定义 CLI 命令
在本文中,我们将探讨如何使用 Symfony Console 组件在我们的 PHP 应用程序中创建自定义命令行界面 (CLI) 命令。 安装必要的库后,我们将创建一些示例来演示控制台组件的概念。
事实上,这个组件被多个 PHP 框架用于开发 CLI 应用程序,并且一些流行的框架已经在使用这个组件作为起点。
什么是 Console 组件?
Symfony Console 组件允许我们在 PHP 应用程序中创建自定义 CLI 命令。 如果我们曾经使用过 Laravel 或 Symfony,我们可能知道它们提供的 CLI 工具可以简化日常操作,例如:
- 生成脚手架代码
- 清除缓存
- 安装、启用和禁用附加服务
- 运行数据库迁移
例如,在 Laravel 的情况下,它带有 artisan
工具,该工具提供了大量实用命令,使我们的生活更轻松。 你可能会惊讶地发现 artisan
工具是建立在 Symfony Console 组件之上的! 事实上,有许多框架利用控制台组件来构建它们的命令行工具。
在本文中,我们将探讨 Console 组件的基础知识,以便我们可以在 PHP 应用程序中创建自定义 CLI 命令。 首先,我们将使用 Composer 安装控制台组件。 安装后,我们将构建一些示例以供演示。
安装和配置
在本节中,我们将安装 Console 组件,这是在 PHP 应用程序中创建 CLI 命令所必需的。 我假设大家已经在系统中安装了 Composer——我们需要它来安装 Packagist 提供的 Console 组件。
安装 Composer 后,继续使用以下命令安装控制台组件。
$ composer require symfony/console
那应该已经创建了 composer.json 文件,它应该如下所示:
composer.json
{ "require": { "symfony/console": "^5.4" } }
让我们将 composer.json 文件修改为如下所示:
composer.json
{ "require": { "symfony/console": "^5.4" }, "autoload": { "psr-4": { "Console\\": "src" }, "classmap": ["src"] } }
由于我们添加了一个新的类映射条目,让我们继续运行以下命令来更新 Composer 自动加载器。
$ composer dump -o
现在,我们可以使用 Console 命名空间自动加载 src 目录下的类。
的第一个 HelloWorld 命令
使用 Console 组件创建 CLI 命令是一个两步过程。
- 首先,我们需要创建一个控制台应用程序来加载必要的依赖项并注册我们的自定义命令。
- 接下来,我们需要为控制台应用程序中注册的所有命令创建单独的文件。
创建控制台应用程序
在本节中,我们将创建自定义控制台应用程序。 我们的控制台应用程序的建议目录结构如下所示。
|-- bin
| `-- console
|-- composer.json
|-- composer.lock
|-- src
| `-- App
| `-- Commands
| |-- ClearcacheCommand.php
| `-- HelloworldCommand.php
`-- vendor
继续并使用以下内容创建主应用程序文件 bin/console。 请注意没有文件扩展名,还要确保它也是可执行的,因为我们需要从命令行运行它。
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
$app = new Application();
$app->run();
#!/usr/bin/env php
文件中的第一行确保它在 PHP 环境下运行。 继续尝试运行它,看看它是如何进行的。
$bin/console
Console Tool
Usage:
command [options] [arguments]
Options:
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
completion Dump the shell completion script
help Display help for a command
list List commands
不错! 只需几行代码,我们就可以使用自定义控制台应用程序! 但它目前没有做任何有用的事情。 在下一节中,我们将了解如何创建自定义命令并将它们注册到我们的自定义控制台应用程序中。
创建 Hello World 命令文件
让我们继续创建我们的第一个自定义命令:HelloworldCommand
。 使用以下内容创建 src/App/Commands/HelloworldCommand.php 文件。
src/App/Commands/HelloworldCommand.php
namespace Console\App\Commands; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; class HelloworldCommand extends Command { protected function configure() { $this->setName('hello-world') ->setDescription('Prints Hello-World!') ->setHelp('Demonstration of custom commands created by Symfony Console component.') ->addArgument('username', InputArgument::REQUIRED, 'Pass the username.'); } protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln(sprintf('Hello World!, %s', $input->getArgument('username'))); return Command::SUCCESS; } }
在创建自定义命令时,我们应该创建两个主要方法:配置和执行。
顾名思义,configure
方法允许我们配置命令,以便我们可以设置命令名称、命令的简短描述、帮助文本等。 如果要在运行命令时传递参数,还可以为命令配置参数。
在上面的示例中,命令名称设置为 hello-world。 此外,我们希望将用户名作为第一个参数传递,因此我们使用 addArgument 方法对其进行了配置。 此外,由于我们在第二个参数中传递了 InputArgument::REQUIRED
,因此用户在执行此命令时必须传递此参数,否则该命令将不会执行并会导致错误。
另一方面,execute
方法包含命令的应用逻辑。 在我们的例子中,我们通过将 Hello World 显示为命令的输出来保持它非常简单。
同样重要的是要注意
execute
方法必须返回一个整数,它将用作命令退出状态。 因此,我们将Command::SUCCESS
作为此命令的返回值传递,这表明命令已成功执行。 您还可以使用其他可用状态,例如Command::FAILURE
和Command::INVALID
。
在运行此命令之前,我们需要将其注册到我们在上一节中创建的控制台应用程序。 让我们快速修改 bin/console 文件,如下所示。
bin/console
#!/usr/bin/env php <?php require_once __DIR__ . '/../vendor/autoload.php'; use Symfony\Component\Console\Application; use Console\App\Commands\HelloworldCommand; $app = new Application(); $app->add(new HelloworldCommand()); $app->run();
如大家所见,我们使用了 Application 对象的 add
方法来添加 HelloworldCommand
命令。 让我们快速列出所有可用的命令。
Console Tool
Usage:
command [options] [arguments]
Options:
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
completion Dump the shell completion script
hello-world Prints Hello-World!
help Display help for a command
list List commands
正如预期的那样,hello-world 命令出现在可用命令列表中! 继续运行吧!
$bin/console hello-world jiyik
Hello World!, jiyik
一个真实的例子:清除缓存命令
在上一节中,我们构建了 hello-world 命令来演示控制台组件的概念。 在本节中,我们将创建一个真实世界的示例来演示如何构建一个命令来清除应用程序中的缓存。
创建清除缓存命令文件
继续并使用以下内容创建 src/App/Commands/ClearcacheCommand.php 文件。
src/App/Commands/ClearcacheCommand.php
namespace Console\App\Commands; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; class ClearcacheCommand extends Command { protected function configure() { $this->setName('clear-cache') ->setDescription('Clears the application cache.') ->setHelp('Allows you to delete the application cache. Pass the --groups parameter to clear caches of specific groups.') ->addOption( 'groups', 'g', InputOption::VALUE_OPTIONAL, 'Pass the comma separated group names if you don\'t want to clear all caches.', '' ); } protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Cache is about to cleared...'); if ($input->getOption('groups')) { $groups = explode(",", $input->getOption('groups')); if (is_array($groups) && count($groups)) { foreach ($groups as $group) { $output->writeln(sprintf('%s cache is cleared', $group)); } } } else { $output->writeln('All caches are cleared.'); } $output->writeln('Complete.'); return Command::SUCCESS; } }
configure
方法几乎相同,除了我们使用 addOption
方法向我们的命令添加一个选项。 因此,我们可以使用 --groups
参数传递组值。
另一方面,execute
方法包含我们命令的应用逻辑。
如果要清除特定组的缓存,需要将组名与
--group
参数一起传递。 另一方面,如果要清除所有缓存,请跳过--group
参数。 我们可能已经注意到,我们通过在addOption
方法的第三个参数中提供InputOption::VALUE_OPTIONAL
值,使--group
参数保持可选。
使用控制台应用程序注册和测试
在我们运行它之前,让我们用我们的控制台应用程序注册命令。
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
use Console\App\Commands\HelloworldCommand;
use Console\App\Commands\ClearcacheCommand;
$app = new Application();
$app->add(new HelloworldCommand());
$app->add(new ClearcacheCommand());
$app->run();
现在,继续运行 bin/console clear-cache
命令来清除所有缓存!
$ bin/console clear-cache
Cache is about to cleared...
All caches are cleared.
Complete.
接下来,如果你想清除特定的缓存,你可以尝试这样的事情。
$ bin/console clear-cache --groups=group1,group2
Cache is about to cleared...
group1 cache is cleared
group2 cache is cleared
Complete.
当然,我们需要实现清除缓存的实际逻辑,但这应该是一个很好的起点。
如何为命令添加进度条
当我们准备可能需要很长时间才能运行的命令时,显示进度信息很有用。 在本节中,我们将快速了解如何向命令添加进度条。
我们将重新审视我们在上一节中讨论的示例。 让我们用以下内容替换 src/App/Commands/ClearcacheCommand.php 文件。
src/App/Commands/ClearcacheCommand.php
namespace Console\App\Commands; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Helper\ProgressBar; class ClearcacheCommand extends Command { protected function configure() { $this->setName('clear-cache') ->setDescription('Clears the application cache.') ->setHelp('Allows you to delete the application cache. Pass the --groups parameter to clear caches of specific groups.') ->addOption( 'groups', 'g', InputOption::VALUE_OPTIONAL, 'Pass the comma separated group names if you don\'t want to clear all caches.', '' ); } protected function execute(InputInterface $input, OutputInterface $output) { if ($input->getOption('groups')) { $groups = explode(",", $input->getOption('groups')); $progressBar = new ProgressBar($output, count($groups)); $progressBar->start(); if (is_array($groups) && count($groups)) { foreach ($groups as $group) { sleep(5); $progressBar->advance(); } } $progressBar->finish(); } else { $output->writeln('All caches are cleared.'); } $output->writeln(''); return Command::SUCCESS; } }
我们使用 Symfony\Component\Console\Helper\ProgressBar
类来实现进度条。
接下来,我们使用以下语句初始化了进度条。
$progressBar = new ProgressBar($output, count($groups));
在第一个参数中,需要传递 $output 对象,第二个参数是进度条中的总单位数。 在我们的例子中,我们将计算用户想要清除的缓存组的数量,并在第二个参数中传递相同的数字。
接下来,我们需要使用 start
方法启动进度条。 要使进度条前进,我们需要使用 advance
方法。 最后,finish
方法完成进度条。 因此,每当命令成功完成时,我们都可以调用此方法,以便进度条刷新为 100% 完成。
在我们的示例中,我们使用了 sleep
命令,因此您可以在命令执行期间看到进度条。
继续并运行 clear-cache
命令,如以下代码片段所示,它应该显示进度条。
$bin/console clear-cache --groups=group1,group2,group3,group4,group5
5/5 [==============================] 100%
由于我们在 --groups
选项中传递了五个组,进度条被初始化为五个单位。 按照我们的逻辑,进度条应该每五秒增加 20% ,25 秒后会达到 **100%**。
这就是我们可以使用命令实现进度条的方式。
总结
今天,我们了解了 Symfony 框架提供的一种流行组件:Console 组件。 如果我们希望开发自己的 CLI 应用程序以帮助我们轻松执行日常实用程序任务,它确实是一个有用的组件。
相关文章
使用 PHP MySQLi 函数获取最后插入的 ID
发布时间:2023/05/09 浏览次数:85 分类:MySQL
-
本篇文章简要介绍了 PHP mysqli() 函数并演示了如何使用它从 MySQL 数据库中获取最后插入的 ID。它是一个名为 mysqli 的 MySQL 驱动程序扩展版本,
在 PHP 中使用 MongoDB 作为文件存储
发布时间:2023/04/20 浏览次数:133 分类:MongoDB
-
在为大文件创建可扩展存储方面,MongoDB 及其 GridFS(使用 MongoDB 查询语言 - MQL 编写)是市场上最好的文件存储解决方案之一。 在本教程中,您将学习如何在 PHP 中使用 MongoDB 作为文件存储。
如何在 PHP 中获取时间差的分钟数
发布时间:2023/03/29 浏览次数:183 分类:PHP
-
本文介绍了如何在 PHP 中获取时间差的分钟数,包括 date_diff()函数和数学公式。它包括 date_diff()函数和数学公式。