Artisan Console
Artisan Console
Artisan 是 Laravel 提供的命令行工具,提供了许多的内置命令,使用 list 可以查看可用的命令:
php artisan list编写自定义命令
单独类命令
命令通常保存在 app/Console/Commands 目录下,不过也可以在 bootstrap/app.php 中通过 withCommands 方法注册命令位置。
要创建一个命令,可以使用 make:command 命令:
php artisan make:command ExpireScore生成命令后,应该为这个类的 signature 和 description 属性定义合适的值,handle 方法将在命令执行时被调用:
class ExpireScore extends Command
{
protected $signature = 'member:expire-score';
protected $description = 'expire score daily';
public function handle(OrderService $orderService)
{
$this->info($orderService->genOrderNumber());
}
}handle 方法同样可以通过类型提示来注入依赖,接下来可以执行上面这个命令:
php artisan member:expire-scorehandle 方法如果没有返回值且命令执行成功,那么此命令将以 0 作为退出状态码返回,也可以手动返回一个整数作为退出状态码。
如果想在任意地方使命令失败,可以使用 fail 方法:
public function handle()
{
$this->fail('123');
}闭包命令
就像路由一样,命令也可以使用闭包来定义而不需要单独的类,闭包命令定义在 routes/console.php 文件中,通过 bootstrap/app.php 同样可以修改这个文件的位置,例如注册一个闭包命令:
Artisan::command('order:generate-number', function (OrderService $orderService) {
$this->info($orderService->genOrderNumber());
});闭包方法将会绑定到基础命令的类实例上,所以闭包内可以使用 $this 来访问 Artisan 命令实例。
如果需要为一个闭包命令定义描述,可以使用 purpose 方法:
Artisan::command('order:generate-number', function (OrderService $orderService) {
$this->info($orderService->genOrderNumber());
})->purpose('Generate order number');输入输出
定义输入参数
所有的参数都应该包含在花括号 {} 中,例如:
protected $signature = 'order:generate-number {count}';上面的参数是必填的,也可以定义为可选参数或者定义默认值,例如:
protected $signature = 'order:generate-number {count?}';
protected $signature = 'order:generate-number {count=1}';如果要定义选项,可以使用 -- 前缀,例如:
protected $signature = 'order:generate-number {count?} {--queue}';选项将会被解析为布尔值,如果要定义选项的值,可以使用 =,例如:
protected $signature = 'order:generate-number {count?} {--queue=}';如果使用了 = 的选项没有在执行命令时提供值,那么这个选项将会被解析为 null。
选项同样也可以指定默认值,例如:
protected $signature = 'order:generate-number {count?} {--queue=1}';如果希望输入数组,那么可以使用 *,例如:
protected $signature = 'member:expire-score {arr*}';选项同样可以指定数组,例如:
protected $signature = 'member:expire-score {--arr=*}';如果一个命令包含了必填参数,那么在未提供这些参数时,Artisan 会提示错误信息,或者实现 PromptsForMissingArguments 接口来在不提供必填参数时提示用户输入:
class ExpireScore extends Command implements PromptsForMissingInput实现这个接口后,Artisan 会在不提供必填参数时提示用户输入这些参数,如果希望自定义提示信息,可以重写 promptForMissingArgumentsUsing 方法:
protected function promptForMissingArgumentsUsing()
{
return [
'arg' => 'set the arg',
];
}获取参数
使用 argument、arguments、option、options 方法可以获取参数:
public function handle(OrderService $orderService)
{
$this->info(json_encode([
'args' => $this->arguments(),
'arg' => $this->argument('arg'),
'opts' => $this->options(),
'opt' => $this->option('opt'),
]));
}如果希望提示用户输入参数,可以使用 ask 方法或者 secret 方法,secret 方法会隐藏输入内容:
public function handle(OrderService $orderService)
{
$username = $this->ask('username');
$password = $this->secret('password');
$this->info(json_encode([
'username' => $username,
'password' => $password,
]));
}如果希望在执行下一步前提示用户确认,可以使用 confirm 方法,此方法将返回一个布尔值,如果用户输入 y 或 yes,则返回 true,否则返回 false,默认返回 false:
public function handle(OrderService $orderService)
{
$username = $this->ask('username');
$password = $this->secret('password');
$ok = $this->confirm('print info?');
if (!$ok) {
return;
}
$this->info(json_encode([
'username' => $username,
'password' => $password,
]));
}如果希望输入一个参数时提供自动完成功能,可以使用 anticipate 方法:
$username = $this->anticipate('username', ['admin', 'test']);提示
无论自动完成的结果是什么,用户仍然可以输入任意值。
这个方法也可以接收一个闭包作为第二个参数,闭包会接收一个包含用户目前输入的字符串,同时返回一个选项数组:
public function handle(OrderService $orderService)
{
$name = $this->anticipate('username', function (string $input): array {
return Member::query()
->whereLike('name', $input . '%')
->limit(3)
->pluck('name')
->all();
});
$this->info($name);
}如果一个参数是一个选项,那么可以使用 choice 方法,此方法可以通过指定下标来设置默认值:
$level = $this->choice('log level', ['info', 'warn', 'error'], 1);
call_user_func_array([$this, $level], [$name]);输出
使用 info、warn、error 可以输出包含颜色的文本,使用 line 方法可以输出不包含颜色的文本,使用 newLine 方法可以输出空行。
注册命令
默认情况下,Laravel 会自动注册 app/Console/Commands 目录下的命令,如果希望扫描其他目录下的命令,可以通过修改 bootstrap/app.php 中的 withCommands 方法来实现:
->withCommands([
__DIR__ . '../app/Jobs',
])或者直接把类名注册到这个方法中:
->withCommands([
ExpireScore::class,
])代码中执行命令
如果希望在代码中而不是命令行来执行命令,可以使用 call 方法:
public function expireScore(Request $request)
{
$params = $this->getParams($request);
$exitCode = Artisan::call('member:expire-score', $params);
return $exitCode;
}信号处理
操作系统允许将信号发送到正在运行的进程,Artisan 也提供了信号处理功能,可以使用 trap 方法来处理信号:
public function handle(OrderService $orderService)
{
$this->trap(SIGTERM, function () {
$this->terminated = true;
});
while (true) {
if ($this->terminated) {
$this->warn('exit');
break;
}
$this->info('running');
sleep(1);
}
}然后使用 kill 命令发送信号即可实现进程的退出。