命令行

Hyperf 的命令行默认由 hyperf/command 组件提供,而该组件本身也是基于 symfony/console 的抽象。

安装

通常来说该组件会默认存在,但如果您希望用于非 Hyperf 项目,也可通过下面的命令依赖 hyperf/command 组件:

  1. composer require hyperf/command

查看命令列表

直接运行 php bin/hyperf.php 不带任何的参数即为输出命令列表。

自定义命令

生成命令

如果你有安装 hyperf/devtool 组件的话,可以通过 gen:command 命令来生成一个自定义命令:

  1. php bin/hyperf.php gen:command FooCommand

执行上述命令后,便会在 app/Command 文件夹内生成一个配置好的 FooCommand 类了。

定义命令

定义该命令类所对应的命令有两种形式,一种是通过 $name 属性定义,另一种是通过构造函数传参来定义,我们通过代码示例来演示一下,假设我们希望定义该命令类的命令为 foo:hello

$name 属性定义:

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Command;
  4. use Hyperf\Command\Command as HyperfCommand;
  5. use Hyperf\Command\Annotation\Command;
  6. #[Command]
  7. class FooCommand extends HyperfCommand
  8. {
  9. /**
  10. * 执行的命令行
  11. */
  12. protected string $name = 'foo:hello';
  13. }

构造函数传参定义:

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Command;
  4. use Hyperf\Command\Command as HyperfCommand;
  5. use Hyperf\Command\Annotation\Command;
  6. #[Command]
  7. class FooCommand extends HyperfCommand
  8. {
  9. public function __construct()
  10. {
  11. parent::__construct('foo:hello');
  12. }
  13. }

定义命令类逻辑

命令类实际运行的逻辑是取决于 handle 方法内的代码,也就意味着 handle 方法就是命令的入口。

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Command;
  4. use Hyperf\Command\Command as HyperfCommand;
  5. use Hyperf\Command\Annotation\Command;
  6. #[Command]
  7. class FooCommand extends HyperfCommand
  8. {
  9. /**
  10. * 执行的命令行
  11. */
  12. protected string $name = 'foo:hello';
  13. public function handle()
  14. {
  15. // 通过内置方法 line 在 Console 输出 Hello Hyperf.
  16. $this->line('Hello Hyperf.', 'info');
  17. }
  18. }

定义命令类的参数

在编写命令时,通常是通过 参数选项 来收集用户的输入的,在收集一个用户输入前,必须对该 参数选项 进行定义。

参数

假设我们希望定义一个 name 参数,然后通过传递任意字符串如 Hyperf 于命令一起并执行 php bin/hyperf.php foo:hello Hyperf 输出 Hello Hyperf,我们通过代码来演示一下:

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Command;
  4. use Hyperf\Command\Annotation\Command;
  5. use Hyperf\Command\Command as HyperfCommand;
  6. use Symfony\Component\Console\Input\InputArgument;
  7. #[Command]
  8. class FooCommand extends HyperfCommand
  9. {
  10. /**
  11. * 执行的命令行
  12. */
  13. protected string $name = 'foo:hello';
  14. public function handle()
  15. {
  16. // 从 $input 获取 name 参数
  17. $argument = $this->input->getArgument('name') ?? 'World';
  18. $this->line('Hello ' . $argument, 'info');
  19. }
  20. protected function getArguments()
  21. {
  22. return [
  23. ['name', InputArgument::OPTIONAL, '这里是对这个参数的解释']
  24. ];
  25. }
  26. }

执行 php bin/hyperf.php foo:hello Hyperf 我们就能看到输出了 Hello Hyperf 了。

命令常用配置介绍

以下代码皆只修改 configurehandle 中的内容。

设置 Help

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->setHelp('Hyperf 自定义命令演示');
  5. }
  6. $ php bin/hyperf.php demo:command --help
  7. ...
  8. Help:
  9. Hyperf 自定义命令演示

设置 Description

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->setDescription('Hyperf Demo Command');
  5. }
  6. $ php bin/hyperf.php demo:command --help
  7. ...
  8. Description:
  9. Hyperf Demo Command

设置 Usage

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->addUsage('--name 演示代码');
  5. }
  6. $ php bin/hyperf.php demo:command --help
  7. ...
  8. Usage:
  9. demo:command
  10. demo:command --name 演示代码

设置参数

参数支持以下模式。

模式 备注
InputArgument::REQUIRED 1 参数必填,此种模式 default 字段无效
InputArgument::OPTIONAL 2 参数可选,常配合 default 使用
InputArgument::IS_ARRAY 4 数组类型

可选类型

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->addArgument('name', InputArgument::OPTIONAL, '姓名', 'Hyperf');
  5. }
  6. public function handle()
  7. {
  8. $this->line($this->input->getArgument('name'));
  9. }
  10. $ php bin/hyperf.php demo:command
  11. ...
  12. Hyperf
  13. $ php bin/hyperf.php demo:command Swoole
  14. ...
  15. Swoole

数组类型

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->addArgument('name', InputArgument::IS_ARRAY, '姓名');
  5. }
  6. public function handle()
  7. {
  8. var_dump($this->input->getArgument('name'));
  9. }
  10. $ php bin/hyperf.php demo:command Hyperf Swoole
  11. ...
  12. array(2) {
  13. [0]=>
  14. string(6) "Hyperf"
  15. [1]=>
  16. string(6) "Swoole"
  17. }

设置选项

选项支持以下模式。

模式 备注
InputOption::VALUE_NONE 1 是否传入可选项 default 字段无效
InputOption::VALUE_REQUIRED 2 选项必填
InputOption::VALUE_OPTIONAL 4 选项可选
InputOption::VALUE_IS_ARRAY 8 选项数组

是否传入可选项

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->addOption('opt', 'o', InputOption::VALUE_NONE, '是否优化');
  5. }
  6. public function handle()
  7. {
  8. var_dump($this->input->getOption('opt'));
  9. }
  10. $ php bin/hyperf.php demo:command
  11. bool(false)
  12. $ php bin/hyperf.php demo:command -o
  13. bool(true)
  14. $ php bin/hyperf.php demo:command --opt
  15. bool(true)

选项必填和可选

VALUE_OPTIONAL 在单独使用上与 VALUE_REQUIRED 并无二致

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->addOption('name', 'N', InputOption::VALUE_REQUIRED, '姓名', 'Hyperf');
  5. }
  6. public function handle()
  7. {
  8. var_dump($this->input->getOption('name'));
  9. }
  10. $ php bin/hyperf.php demo:command
  11. string(6) "Hyperf"
  12. $ php bin/hyperf.php demo:command --name Swoole
  13. string(6) "Swoole"

选项数组

VALUE_IS_ARRAYVALUE_OPTIONAL 配合使用,可以达到传入多个 Option 的效果。

  1. public function configure()
  2. {
  3. parent::configure();
  4. $this->addOption('name', 'N', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, '姓名');
  5. }
  6. public function handle()
  7. {
  8. var_dump($this->input->getOption('name'));
  9. }
  10. $ php bin/hyperf.php demo:command
  11. array(0) {
  12. }
  13. $ php bin/hyperf.php demo:command --name Hyperf --name Swoole
  14. array(2) {
  15. [0]=>
  16. string(6) "Hyperf"
  17. [1]=>
  18. string(6) "Swoole"
  19. }

通过 $signature 配置命令行

命令行除了上述配置方法外,还支持使用 $signature 配置。

$signature 为字符串,分为三部分,分别是 command argumentoption,如下:

  1. command:name {argument?* : The argument description.} {--option=* : The option description.}
  • ? 代表 非必传
  • * 代表 数组
  • ?* 代表 非必传的数组
  • = 代表 非 Bool

示例

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Command;
  4. use Hyperf\Command\Annotation\Command;
  5. use Hyperf\Command\Command as HyperfCommand;
  6. use Psr\Container\ContainerInterface;
  7. #[Command]
  8. class DebugCommand extends HyperfCommand
  9. {
  10. protected ContainerInterface $container;
  11. protected $signature = 'test:test {id : user_id} {--name= : user_name}';
  12. public function __construct(ContainerInterface $container)
  13. {
  14. $this->container = $container;
  15. parent::__construct();
  16. }
  17. public function configure()
  18. {
  19. parent::configure();
  20. $this->setDescription('Hyperf Demo Command');
  21. }
  22. public function handle()
  23. {
  24. var_dump($this->input->getArguments());
  25. var_dump($this->input->getOptions());
  26. }
  27. }

运行命令

!> 注意:在运行命令时,默认不会触发事件分发,可通过添加 --enable-event-dispatcher 参数来开启。

命令行中运行

  1. php bin/hyperf.php foo

在 Command 中运行其他命令

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Command;
  4. use Hyperf\Command\Command as HyperfCommand;
  5. use Hyperf\Command\Annotation\Command;
  6. use Psr\Container\ContainerInterface;
  7. #[Command]
  8. class FooCommand extends HyperfCommand
  9. {
  10. protected ContainerInterface $container;
  11. public function __construct(ContainerInterface $container)
  12. {
  13. $this->container = $container;
  14. parent::__construct('foo');
  15. }
  16. public function configure()
  17. {
  18. parent::configure();
  19. $this->setDescription('foo command');
  20. }
  21. public function handle()
  22. {
  23. $this->call('bar', [
  24. '--foo' => 'foo'
  25. ]);
  26. }
  27. }

在非 Command 中运行命令

  1. $command = 'foo';
  2. $params = ["command" => $command, "--foo" => "foo", "--bar" => "bar"];
  3. // 可以根据自己的需求, 选择使用的 input/output
  4. $input = new ArrayInput($params);
  5. $output = new NullOutput();
  6. /** @var \Psr\Container\ContainerInterface $container */
  7. $container = \Hyperf\Utils\ApplicationContext::getContainer();
  8. /** @var \Symfony\Component\Console\Application $application */
  9. $application = $container->get(\Hyperf\Contract\ApplicationInterface::class);
  10. $application->setAutoExit(false);
  11. // 这种方式: 不会暴露出命令执行中的异常, 不会阻止程序返回
  12. $exitCode = $application->run($input, $output);
  13. // 第二种方式: 会暴露异常, 需要自己捕捉和处理运行中的异常, 否则会阻止程序的返回
  14. $exitCode = $application->find($command)->run($input, $output);