Skip to content

Artisan 控制台

介绍

Artisan 是 Laravel 附带的命令行界面。它提供了许多有用的命令,可以在构建应用程序时为您提供帮助。要查看所有可用的 Artisan 命令列表,可以使用 list 命令:

php
php artisan list

每个命令还包括一个“帮助”屏幕,显示并描述命令的可用参数和选项。要查看帮助屏幕,只需在命令名称前加上 help

php
php artisan help migrate

Laravel REPL

所有 Laravel 应用程序都包含 Tinker,这是一个由 PsySH 包提供支持的 REPL。Tinker 允许您在命令行上与整个 Laravel 应用程序交互,包括 Eloquent ORM、作业、事件等。要进入 Tinker 环境,请运行 tinker Artisan 命令:

php
php artisan tinker

编写命令

除了 Artisan 提供的命令外,您还可以构建自己的自定义命令。命令通常存储在 app/Console/Commands 目录中;但是,您可以自由选择自己的存储位置,只要您的命令可以被 Composer 加载即可。

生成命令

要创建新命令,请使用 make:command Artisan 命令。此命令将在 app/Console/Commands 目录中创建一个新的命令类。如果您的应用程序中不存在此目录,请不要担心,因为它将在您第一次运行 make:command Artisan 命令时创建。生成的命令将包括所有命令中存在的默认属性和方法集:

php
php artisan make:command SendEmails

接下来,您需要在 Artisan CLI 中执行命令之前注册命令

命令结构

生成命令后,您应填写类的 signaturedescription 属性,这些属性将在 list 屏幕上显示您的命令时使用。执行命令时将调用 handle 方法。您可以将命令逻辑放在此方法中。

lightbulb

为了更好的代码重用,建议保持控制台命令轻量,并让它们委托给应用程序服务来完成任务。在下面的示例中,请注意我们注入了一个服务类来完成发送电子邮件的“繁重工作”。

让我们看一个示例命令。请注意,我们可以将所需的任何依赖项注入到命令的构造函数中。Laravel 服务容器 将自动注入构造函数中类型提示的所有依赖项:

php
<?php

namespace App\Console\Commands;

use App\User;
use App\DripEmailer;
use Illuminate\Console\Command;

class SendEmails extends Command
{
    /**
     * 控制台命令的名称和签名。
     *
     * @var string
     */
    protected $signature = 'email:send {user}';

    /**
     * 控制台命令描述。
     *
     * @var string
     */
    protected $description = '向用户发送滴灌电子邮件';

    /**
     * 滴灌电子邮件服务。
     *
     * @var DripEmailer
     */
    protected $drip;

    /**
     * 创建新的命令实例。
     *
     * @param  DripEmailer  $drip
     * @return void
     */
    public function __construct(DripEmailer $drip)
    {
        parent::__construct();

        $this->drip = $drip;
    }

    /**
     * 执行控制台命令。
     *
     * @return mixed
     */
    public function handle()
    {
        $this->drip->send(User::find($this->argument('user')));
    }
}

闭包命令

基于闭包的命令提供了定义控制台命令的类的替代方案。就像路由闭包是控制器的替代方案一样,可以将命令闭包视为命令类的替代方案。在 app/Console/Kernel.php 文件的 commands 方法中,Laravel 加载 routes/console.php 文件:

php
/**
 * 为应用程序注册基于闭包的命令。
 *
 * @return void
 */
protected function commands()
{
    require base_path('routes/console.php');
}

即使此文件未定义 HTTP 路由,它也定义了进入应用程序的基于控制台的入口点(路由)。在此文件中,您可以使用 Artisan::command 方法定义所有基于闭包的路由。command 方法接受两个参数: 命令签名 和接收命令参数和选项的闭包:

php
Artisan::command('build {project}', function ($project) {
    $this->info("Building {$project}!");
});

闭包绑定到底层命令实例,因此您可以完全访问通常可以在完整命令类上访问的所有辅助方法。

类型提示依赖项

除了接收命令的参数和选项外,命令闭包还可以类型提示您希望从 服务容器 中解析的其他依赖项:

php
use App\User;
use App\DripEmailer;

Artisan::command('email:send {user}', function (DripEmailer $drip, $user) {
    $drip->send(User::find($user));
});

闭包命令描述

定义基于闭包的命令时,可以使用 describe 方法为命令添加描述。当您运行 php artisan listphp artisan help 命令时,将显示此描述:

php
Artisan::command('build {project}', function ($project) {
    $this->info("Building {$project}!");
})->describe('Build the project');

定义输入期望

编写控制台命令时,通常需要通过参数或选项从用户那里收集输入。Laravel 使您可以非常方便地使用命令上的 signature 属性定义您期望用户提供的输入。signature 属性允许您以一种简单、类似路由的语法定义命令的名称、参数和选项。

参数

所有用户提供的参数和选项都用大括号括起来。在以下示例中,命令定义了一个必需参数:user

php
/**
 * 控制台命令的名称和签名。
 *
 * @var string
 */
protected $signature = 'email:send {user}';

您还可以使参数可选并为参数定义默认值:

php
// 可选参数...
email:send {user?}

// 带默认值的可选参数...
email:send {user=foo}

选项

选项与参数一样,是另一种形式的用户输入。选项在命令行上指定时以两个连字符(--)为前缀。选项有两种类型:接收值的选项和不接收值的选项。不接收值的选项用作布尔“开关”。让我们看一个这种类型选项的示例:

php
/**
 * 控制台命令的名称和签名。
 *
 * @var string
 */
protected $signature = 'email:send {user} {--queue}';

在此示例中,可以在调用 Artisan 命令时指定 --queue 开关。如果传递了 --queue 开关,则选项的值将为 true。否则,值将为 false

php
php artisan email:send 1 --queue

带值的选项

接下来,让我们看一个期望值的选项。如果用户必须为选项指定一个值,请在选项名称后加上 = 符号:

php
/**
 * 控制台命令的名称和签名。
 *
 * @var string
 */
protected $signature = 'email:send {user} {--queue=}';

在此示例中,用户可以这样传递选项的值:

php
php artisan email:send 1 --queue=default

您可以通过在选项名称后指定默认值来为选项分配默认值。如果用户未传递选项值,则将使用默认值:

php
email:send {user} {--queue=default}

选项快捷方式

要在定义选项时分配快捷方式,可以在选项名称之前指定它,并使用 | 分隔符将快捷方式与完整选项名称分开:

php
email:send {user} {--Q|queue}

输入数组

如果您希望定义参数或选项以期望数组输入,可以使用 * 字符。首先,让我们看一个指定数组参数的示例:

php
email:send {user*}

调用此方法时,可以按顺序将 user 参数传递给命令行。例如,以下命令将 user 的值设置为 ['foo', 'bar']

php
php artisan email:send foo bar

定义期望数组输入的选项时,传递给命令的每个选项值都应以选项名称为前缀:

php
email:send {user} {--id=*}

php artisan email:send --id=1 --id=2

输入描述

您可以通过使用冒号分隔参数和描述来为输入参数和选项分配描述。如果您需要更多空间来定义命令,请随意将定义分布在多行上:

php
/**
 * 控制台命令的名称和签名。
 *
 * @var string
 */
protected $signature = 'email:send
                        {user : 用户的 ID}
                        {--queue= : 是否应将作业排队}';

命令 I/O

检索输入

在执行命令时,您显然需要访问命令接受的参数和选项的值。为此,您可以使用 argumentoption 方法:

php
/**
 * 执行控制台命令。
 *
 * @return mixed
 */
public function handle()
{
    $userId = $this->argument('user');

    //
}

如果需要将所有参数作为 array 检索,请调用 arguments 方法:

php
$arguments = $this->arguments();

选项可以像参数一样轻松检索,使用 option 方法。要将所有选项作为数组检索,请调用 options 方法:

php
// 检索特定选项...
$queueName = $this->option('queue');

// 检索所有选项...
$options = $this->options();

如果参数或选项不存在,将返回 null

提示输入

除了显示输出外,您还可以在命令执行期间要求用户提供输入。ask 方法将使用给定的问题提示用户,接受他们的输入,然后将用户的输入返回给您的命令:

php
/**
 * 执行控制台命令。
 *
 * @return mixed
 */
public function handle()
{
    $name = $this->ask('What is your name?');
}

secret 方法类似于 ask,但用户的输入在控制台中输入时对他们不可见。此方法在询问密码等敏感信息时很有用:

php
$password = $this->secret('What is the password?');

请求确认

如果需要向用户请求简单的确认,可以使用 confirm 方法。默认情况下,此方法将返回 false。但是,如果用户在提示中输入 yyes,则该方法将返回 true

php
if ($this->confirm('Do you wish to continue?')) {
    //
}

自动完成

anticipate 方法可用于为可能的选择提供自动完成。用户仍然可以选择任何答案,无论自动完成提示如何:

php
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);

多项选择问题

如果需要为用户提供预定义的选择集,可以使用 choice 方法。您可以设置默认值,如果未选择任何选项,则返回该默认值:

php
$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default);

写入输出

要将输出发送到控制台,请使用 lineinfocommentquestionerror 方法。每种方法都将使用适当的 ANSI 颜色来实现其目的。例如,让我们向用户显示一些常规信息。通常,info 方法将在控制台中显示为绿色文本:

php
/**
 * 执行控制台命令。
 *
 * @return mixed
 */
public function handle()
{
    $this->info('Display this on the screen');
}

要显示错误消息,请使用 error 方法。错误消息文本通常以红色显示:

php
$this->error('Something went wrong!');

如果您希望显示纯色、无色的控制台输出,请使用 line 方法:

php
$this->line('Display this on the screen');

表格布局

table 方法使得正确格式化多行/列数据变得容易。只需将标题和行传递给该方法。宽度和高度将根据给定数据动态计算:

php
$headers = ['Name', 'Email'];

$users = App\User::all(['name', 'email'])->toArray();

$this->table($headers, $users);

进度条

对于长时间运行的任务,显示进度指示器可能会有所帮助。使用输出对象,我们可以启动、推进和停止进度条。首先,定义进程将迭代的步骤总数。然后,在处理每个项目后推进进度条:

php
$users = App\User::all();

$bar = $this->output->createProgressBar(count($users));

foreach ($users as $user) {
    $this->performTask($user);

    $bar->advance();
}

$bar->finish();

有关更高级的选项,请查看 Symfony Progress Bar 组件文档

注册命令

完成命令后,您需要在 Artisan 中注册它。所有命令都在 app/Console/Kernel.php 文件中注册。在此文件中,您将找到 commands 属性中的命令列表。要注册命令,只需将命令的类名添加到列表中。当 Artisan 启动时,服务容器将解析此属性中列出的所有命令并在 Artisan 中注册:

php
protected $commands = [
    Commands\SendEmails::class
];

以编程方式执行命令

有时您可能希望在 CLI 之外执行 Artisan 命令。例如,您可能希望从路由或控制器触发 Artisan 命令。您可以使用 Artisan facade 上的 call 方法来实现此目的。call 方法接受命令名称作为第一个参数,并接受命令参数数组作为第二个参数。将返回退出代码:

php
Route::get('/foo', function () {
    $exitCode = Artisan::call('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

    //
});

使用 Artisan facade 上的 queue 方法,您甚至可以将 Artisan 命令排队,以便它们由您的 队列工作者 在后台处理。在使用此方法之前,请确保已配置队列并正在运行队列监听器:

php
Route::get('/foo', function () {
    Artisan::queue('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

    //
});

如果需要为不接受字符串值的选项指定值,例如 migrate:refresh 命令上的 --force 标志,可以传递 truefalse

php
$exitCode = Artisan::call('migrate:refresh', [
    '--force' => true,
]);

从其他命令调用命令

有时您可能希望从现有的 Artisan 命令中调用其他命令。您可以使用 call 方法来实现。此 call 方法接受命令名称和命令参数数组:

php
/**
 * 执行控制台命令。
 *
 * @return mixed
 */
public function handle()
{
    $this->call('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

    //
}

如果您希望调用另一个控制台命令并抑制其所有输出,可以使用 callSilent 方法。callSilent 方法的签名与 call 方法相同:

php
$this->callSilent('email:send', [
    'user' => 1, '--queue' => 'default'
]);