docs/en/command.md
The default command component of Hyperf provided by hyperf/command component, And this component is a abstraction of symfony/console.
This component usually exists by default, but if you want to use it for non-Hyperf projects, you can also rely on the hyperf/command component with the following command:
composer require hyperf/command
Run php bin/hyperf.php without any arguments directly is to display the command list.
If you have the hyperf/devtool component installed, you can generate a custom command with the gen:command command:
php bin/hyperf.php gen:command FooCommand
After executing the above command, a configured FooCommand class will be generated in the app/Command folder.
There are three forms of commands that define the command class. The first is defined by the $name property, the second is defined by the constructor argument, and the last is defined by annotations. We demonstrate this through code examples, assuming we want to define the command. The class command is foo:hello:
$name property:<?php
declare(strict_types=1);
namespace App\Command;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
#[Command]
class FooCommand extends HyperfCommand
{
/**
* The command
*
* @var string
*/
protected ?string $name = 'foo:hello';
}
<?php
declare(strict_types=1);
namespace App\Command;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
#[Command]
class FooCommand extends HyperfCommand
{
public function __construct()
{
parent::__construct('foo:hello');
}
}
<?php
declare(strict_types=1);
namespace App\Command;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
#[Command(name: "foo:hello")]
class FooCommand extends HyperfCommand
{
}
The logic that the command class actually runs depends on the handle method inside the code, which means that the handle method is the entry point to the command.
<?php
declare(strict_types=1);
namespace App\Command;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
#[Command]
class FooCommand extends HyperfCommand
{
/**
* The command
*
* @var string
*/
protected ?string $name = 'foo:hello';
public function handle()
{
// Output Hello Hyperf. in the Console via the built-in method line()
$this->line('Hello Hyperf.', 'info');
}
}
When writing a command, the user's input is usually collected by parameter and option, and the parameter or option must be defined before collecting a user input.
Suppose we want to define a name parameter, and then pass the arbitrary string such as Hyperf to the command and execute php bin/hyperf.php foo:hello Hyperf to output Hello Hyperf. Let's demonstrate it by code:
<?php
declare(strict_types=1);
namespace App\Command;
use Hyperf\Command\Annotation\Command;
use Hyperf\Command\Command as HyperfCommand;
use Symfony\Component\Console\Input\InputArgument;
#[Command]
class FooCommand extends HyperfCommand
{
/**
* The command
*
* @var string
*/
protected ?string $name = 'foo:hello';
public function handle()
{
// Get the name argument from $input
$argument = $this->input->getArgument('name') ?? 'World';
$this->line('Hello ' . $argument, 'info');
}
protected function getArguments()
{
return [
['name', InputArgument::OPTIONAL, 'Here is an explanation of this parameter']
];
}
}
Execute php bin/hyperf.php foo:hello Hyperf command and we can see Hello Hyperf display on Console.
The following code only modifies the content in configure and handle.
public function configure()
{
parent::configure();
$this->setHelp('Hyperf's custom command demonstration');
}
$ php bin/hyperf.php demo:command --help
# output
...
Help:
Hyperf's custom command demonstration
public function configure()
{
parent::configure();
$this->setDescription('Hyperf Demo Command');
}
$ php bin/hyperf.php demo:command --help
# output
...
Description:
Hyperf Demo Command
public function configure()
{
parent::configure();
$this->addUsage('--name Demo Code');
}
$ php bin/hyperf.php demo:command --help
# output
...
Usage:
demo:command
demo:command --name Demo Code
The parameters support the following modes.
| Mode | Value | Note |
|---|---|---|
| InputArgument::REQUIRED | 1 | Parameter is required, the "default" field in this mode is invalid. |
| InputArgument::OPTIONAL | 2 | Parameter is optional and is often used with default |
| InputArgument::IS_ARRAY | 4 | Array type |
public function configure()
{
parent::configure();
$this->addArgument('name', InputArgument::OPTIONAL, 'name', 'Hyperf');
}
public function handle()
{
$this->line($this->input->getArgument('name'));
}
$ php bin/hyperf.php demo:command
# output
...
Hyperf
$ php bin/hyperf.php demo:command Swoole
...
Swoole
public function configure()
{
parent::configure();
$this->addArgument('name', InputArgument::IS_ARRAY, 'name');
}
public function handle()
{
var_dump($this->input->getArgument('name'));
}
$ php bin/hyperf.php demo:command Hyperf Swoole
# output
...
array(2) {
[0]=>
string(6) "Hyperf"
[1]=>
string(6) "Swoole"
}
The options support the following modes.
| Mode | Value | Note |
|---|---|---|
| InputOption::VALUE_NONE | 1 | Parameter is required, the "default" field in this mode is invalid |
| InputOption::VALUE_REQUIRED | 2 | Option is required |
| InputOption::VALUE_OPTIONAL | 4 | Option is optional |
| InputOption::VALUE_IS_ARRAY | 8 | Option is an array |
public function configure()
{
parent::configure();
$this->addOption('opt', 'o', InputOption::VALUE_NONE, 'Whether to optimize');
}
public function handle()
{
var_dump($this->input->getOption('opt'));
}
$ php bin/hyperf.php demo:command
# output
bool(false)
$ php bin/hyperf.php demo:command -o
# output
bool(true)
$ php bin/hyperf.php demo:command --opt
# output
bool(true)
VALUE_OPTIONAL is no different from VALUE_REQUIRED when used alone.
public function configure()
{
parent::configure();
$this->addOption('name', 'N', InputOption::VALUE_REQUIRED, 'name', 'Hyperf');
}
public function handle()
{
var_dump($this->input->getOption('name'));
}
$ php bin/hyperf.php demo:command
# output
string(6) "Hyperf"
$ php bin/hyperf.php demo:command --name Swoole
# output
string(6) "Swoole"
VALUE_IS_ARRAY and VALUE_OPTIONAL, when used together, can achieve the effect of passing multiple Options.
public function configure()
{
parent::configure();
$this->addOption('name', 'N', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'name');
}
public function handle()
{
var_dump($this->input->getOption('name'));
}
$ php bin/hyperf.php demo:command
# output
array(0) {
}
$ php bin/hyperf.php demo:command --name Hyperf --name Swoole
# output
array(2) {
[0]=>
string(6) "Hyperf"
[1]=>
string(6) "Swoole"
}
$signature.In addition to the above configuration methods, the command line also supports using $signature configuration.
$signature is a string, divided into three parts: command, argument, and option, as follows:
command:name {argument?* : The argument description.} {--option=* : The option description.}
? represents optional.* represents array.?* represents optional array.= represents non-Bool.<?php
declare(strict_types=1);
namespace App\Command;
use Hyperf\Command\Annotation\Command;
use Hyperf\Command\Command as HyperfCommand;
use Psr\Container\ContainerInterface;
#[Command]
class DebugCommand extends HyperfCommand
{
protected ContainerInterface $container;
protected ?string $signature = 'test:test {id : user_id} {--name= : user_name}';
public function __construct(ContainerInterface $container)
{
$this->container = $container;
parent::__construct();
}
public function configure()
{
parent::configure();
$this->setDescription('Hyperf Demo Command');
}
public function handle()
{
var_dump($this->input->getArguments());
var_dump($this->input->getOptions());
}
}
!> Note: By default, running the command will trigger event dispatching. You can disable it by adding the --disable-event-dispatcher parameter.
php bin/hyperf.php foo
<?php
declare(strict_types=1);
namespace App\Command;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use Psr\Container\ContainerInterface;
#[Command]
class FooCommand extends HyperfCommand
{
protected ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
parent::__construct('foo');
}
public function configure()
{
parent::configure();
$this->setDescription('foo command');
}
public function handle()
{
$this->call('bar', [
'--foo' => 'foo'
]);
}
}
$command = 'foo';
$params = ["command" => $command, "--foo" => "foo", "--bar" => "bar"];
// You can choose the input/output according to your own needs.
$input = new ArrayInput($params);
$output = new NullOutput();
/** @var \Psr\Container\ContainerInterface $container */
$container = \Hyperf\Context\ApplicationContext::getContainer();
/** @var \Symfony\Component\Console\Application $application */
$application = $container->get(\Hyperf\Contract\ApplicationInterface::class);
$application->setAutoExit(false);
// This method: will not expose exceptions during command execution and will not prevent the program from returning.
$exitCode = $application->run($input, $output);
// Another way: it will expose exceptions and require you to catch and handle runtime exceptions yourself, otherwise it will prevent the program from returning.
$exitCode = $application->find($command)->run($input, $output);
You can quickly define commands in config\console.php.
use Hyperf\Command\Console;
Console::command('hello', function () {
$this->comment('Hello, Hyperf!');
})->describe('This is a demo closure command.');
You can also set crontab for closure command.
use Hyperf\Command\Console;
Console::command('foo', function () {
$this->comment('Hello, Foo!');
})->describe('This is a demo closure command.')->cron('* * * * *');
Console::command('bar', function () {
$this->comment('Hello, Bar!');
})->describe('This is another demo closure command.')->cron('* * * * *', callback: fn($cron) => $cron->setSingleton(true));
You can convert a class into a command by annotating it with AsCommand.
<?php
namespace App\Service;
use Hyperf\Command\Annotation\AsCommand;
use Hyperf\Command\Concerns\InteractsWithIO;
#[AsCommand(signature: 'foo:bar1', handle: 'bar1', description: 'The description of foo:bar1 command.')]
#[AsCommand(signature: 'foo', description: 'The description of foo command.')]
class FooService
{
use InteractsWithIO;
#[AsCommand(signature: 'foo:bar {--bar=1 : Bar Value}', description: 'The description of foo:bar command.')]
public function bar($bar)
{
$this->output?->info('Bar Value: ' . $bar);
return $bar;
}
public function bar1()
{
$this->output?->info(__METHOD__);
}
public function handle()
{
$this->output?->info(__METHOD__);
}
}
$ php bin/hyperf.php
...
foo
foo:bar The description of foo:bar command.
foo:bar1 The description of foo:bar1 command.