Artisan 命令行

未匹配的标注
本文档最新版为 10.x,旧版本可能放弃维护,推荐阅读最新版!

Artisan 命令行

简介

Artisan 是 Laravel 附带的命令行接口。Artisan 以artisan 脚本的形式存在于应用的根目录,并提供了许多有用的命令,这些命令可以在构建应用时为你提供帮助。你可以通过 list 命令查看所有可用的 Artisan 命令:

php artisan list

每个命令都包含了 “帮助” 界面,它会显示和概述命令的可用参数及选项。只需要在命令前加上 help 即可查看命令帮助界面:

php artisan help migrate

Laravel Sail

如果你将 Laravel Sail 用作本地开发环境,记得使用 sail 命令行来调用 Artisan 命令。Sail 将在应用的 Docker 容器中执行 Artisan 命令:

./sail artisan list

Tinker 命令 (REPL)

Laravel Tinker 是为 Laravel 提供的强大的 REPL(交互式解释器),由 PsySH 提供支持。

安装

所有 Laravel 应用都默认包含了 Tinker。不过,你也可以使用 Composer 在你需要时手动安装:

composer require laravel/tinker

技巧:正在寻找一个能与 Laravel 交互的图形用户界面吗? 试试 Tinkerwell

用法

Tinker 让你可以在命令行与你的整个 Laravel 应用进行交互。包括但不限于 Eloquent ORM、任务、事件等。通过运行 Artisan 命令 tinker 进入 Tinker 环境。

php artisan tinker

你可以通过 vendor:publish 命令发布 Tinker 配置文件:

php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"

注意:Dispatchable 类中的 dispatch 辅助函数和 dispatch 方法已被弃用以将任务添加至队列中。因此,当你使用 Tinker 时,请使用 Bus::dispatchQueue::push 来分发任务。

命令白名单

Tinker 采用白名单来确定允许哪些 Artisan 命令可以在 shell 中运行。默认情况下,你可以运行 clear-compilerdownenvinspiremigrateoptimizeup 命令。如果你想将命令添加到白名单,请将该命令添加到 tinker.php 配置文件中的 commands 数组:

'commands' => [
    // App\Console\Commands\ExampleCommand::class,
],

别名黑名单

大多数情况下,Tinker 会在你引入类时自动为其添加别名。然而,你可能不希望为某些类添加别名。你可以在 tinker.php 配置文件中的 dont_alias 数组里列举这些类来完成此操作:

'dont_alias' => [
    App\Models\User::class,
],

编写命令

除 Artisan 提供的命令外,你也可以编写自己的自定义命令。 命令在多数情况下位于 app/Console/Commands 目录中; 不过,只要你的命令可以由 Composer 加载,你就可以自由选择自己的存储位置。

生成命令

要创建新命令,可以使用 make:command Artisan命令。该命令将在 app/Console/Commands 目录中创建一个新的命令类。如果你的应用程序中不存在此目录,请不要担心它将在您第一次运行 make:command 命令时自动创建。

php artisan make:command SendEmails

命令结构

生成命令后,应为该类的 signaturedescription 属性定义适当的值。 当在 list 屏幕上显示命令时,将使用这些属性。signature 属性还允许您定义 命令的输入期望值handle 执行命令时将调用该方法。你可以将命令逻辑放在此方法中。

让我们看一个示例命令。请注意,我们能够通过命令的 handle 方法请求我们需要的任何依赖项。Laravel 服务容器 将自动注入此方法签名中带有类型提示的所有依赖项:

<?php

namespace App\Console\Commands;

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

class SendEmails extends Command
{
    /**
     * 命令名称及签名
     *
     * @var string
     */
    protected $signature = 'mail:send {user}';

    /**
     * 命令描述
     *
     * @var string
     */
    protected $description = 'Send a marketing email to a user';

    /**
     * 创建命令
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * 执行命令
     *
     * @param  \App\Support\DripEmailer  $drip
     * @return mixed
     */
    public function handle(DripEmailer $drip)
    {
        $drip->send(User::find($this->argument('user')));
    }
}

技巧:为了更好地复用代码,请尽量让你的命令类保持轻量并且能够延迟到应用服务中完成。在上面的示例中,我们注入了一个服务类来进行发送电子邮件的「繁重工作」。

闭包命令

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

/**
 * 注册闭包命令
 *
 * @return void
 */
protected function commands()
{
    require base_path('routes/console.php');
}

尽管该文件没有定义 HTTP 路由,但它定义了进入应用程序的基于控制台的入口 (routes) 。在这个文件中,你可以使用 Artisan::command 方法定义所有的闭包路由。 The command 方法接受两个参数:命令名称 和可调用的闭包,闭包接收命令的参数和选项:

Artisan::command('mail:send {user}', function ($user) {
    $this->info("Sending email to: {$user}!");
});

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

类型约束依赖

除了接受命令参数及选项外,命令闭包也可以使用类型约束从 服务容器 中解析其他的依赖关系:

use App\Models\User;
use App\Support\DripEmailer;

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

闭包命令说明

在定义基于闭包的命令时,可以使用 purpose方法向命令添加描述。当你运行 php artisan listphp artisan help 命令时,将显示以下描述:

Artisan::command('mail:send {user}', function ($user) {
    // ...
})->purpose('Send a marketing email to a user');

定义输入期望

在编写控制台命令时,通常是通过参数和选项来收集用户输入的。 Laravel 让你可以非常方便地在 signature 属性中定义你期望用户输入的内容。signature 属性允许使用单一且可读性高,类似路由的语法来定义命令的名称、参数和选项。

参数

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

/**
 * 命令的名称及其签名
 *
 * @var string
 */
protected $signature = 'mail:send {user}';

您亦可创建可选参数或为参数定义默认值:

// 可选参数
mail:send {user?}

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

选项

选项类似于参数,是用户输入的另一种形式。在命令行中指定选项的时候,它们以两个短横线 (--) 作为前缀。这有两种类型的选项:接收值和不接受值。不接收值的选项就像是一个布尔「开关」。让我们看一下这种类型的选项的例子:

/**
 * 命令的名称及其签名
 *
 * @var string
 */
protected $signature = 'mail:send {user} {--queue}';

在这个例子中,在调用 Artisan 命令时可以指定 --queue 的开关。如果传递了 --queue 选项,该选项的值将会是 true。否则,其值将会是 false

php artisan mail:send 1 --queue

带值的选项

接下来,让我们来看一下需要带值的选项。如果用户需要为一个选项指定一个值,则需要在选项名称的末尾追加一个等号 =

/**
 * 命名名称及其签名
 *
 * @var string
 */
protected $signature = 'mail:send {user} {--queue=}';

在这个例子中,用户可以像如下所时的方式传递该选项的值。如果在调用命令时未指定该选项,则其值为 null

php artisan mail:send 1 --queue=default

你可以在选项名称后指定其默认值。如果用户没有传递值给选项,将使用默认的值:

mail:send {user} {--queue=default}

选项简写

要在定义选项的时候指定一个简写,您可以在选项名前面使用 | 隔符将选项名称与其简写分隔开来:

mail:send {user} {--Q|queue}

输入数组

如果您想要接收数组数组的参数或者选项,您可以使用 * 字符。首先,让我们看一下指定了一个数组参数的例子:

mail:send {user*}

当调用这个方法的时候,user 参数的输入参数将按顺序传递给命令。例如,以下命令将会设置 user 的值为 foobar

php artisan mail:send foo bar

* 字符可以与可选的参数结合使用,允许您定义零个或多个参数实例:

mail:send {user?*}

选项数组

当定义需要多个输入值的选项时,传递给命令的每个选项值都应以选项名称作为前缀:

mail:send {user} {--id=*}

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

输入说明

您可以通过使用冒号将参数名称与描述分隔来为输入参数和选项指定说明。如果您需要一些额外的空间来定义命令,可以将它自由的定义在多行中:

/**
 * 控制台命令的名称和签名。
 *
 * @var string
 */
protected $signature = 'mail:send
                        {user : The ID of the user}
                        {--queue= : Whether the job should be queued}';

命令 I/O

检索输入

当命令在执行时,您可能需要访问命令所接受的参数和选项的值。 为此,您可以使用 argument and option 方法。如果选项或参数不存在,null 将会返回:

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

    //
}

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

$arguments = $this->arguments();

选项的检索与参数一样容易,使用option 方法即可。如果要检索所有的选项做为数组,请调用 options 方法:

// 检索一个指定的选项...
$queueName = $this->option('queue');

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

交互式输入

除了显示输出以外,你还可以要求用户在执行命令期间提供输入。ask 方法将询问用户指定的问题来接收用户输入,然后用户输入将会传到你的命令中:

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

secret 方法与 ask 相似,区别在于用户的输入将不可见。这个方法在需要输入一些诸如密码之类的敏感信息时是非常有用的:

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

请求确认

如果你需要请求用户进行一个简单的确认,可以使用 confirm 方法来实现。默认情况下,这个方法会返回 false。当然,如果用户输入 yyes,这个方法将会返回 true

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

如有必要,你可以通过将 true 作为第二个参数传递给 confirm 方法,这样就可以在默认情况下返回 true

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

自动补全

anticipate 方法可用于为可能的选项提供自动补全功能。用户依然可以忽略自动补全的提示,进行任意回答:

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

或者,你可以将一个闭包作为第二个参数传递给 anticipate 方法。每当用户键入字符时,闭包函数都会被调用。闭包函数应该接受一个包含用户输入的字符串形式的参数,并返回一个可供自动补全的选项的数组:

$name = $this->anticipate('What is your address?', function ($input) {
    // 返回自动完成配置
});

多选择问题

当询问问题时,如果您需要给用户一个预定义的选择,您可以使用 choice 方法。 如果没有选项被选择,您可以设置数组索引的默认值去返回,通过这个方法的第三个参数去传入索引:

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

此外, choice 方法接受第四和第五可选参数 ,用于确定选择有效响应的最大尝试次数以及是否允许多次选择:

$name = $this->choice(
    'What is your name?',
    ['Taylor', 'Dayle'],
    $defaultIndex,
    $maxAttempts = null,
    $allowMultipleSelections = false
);

文字输出

您可以使用 lineinfocommentquestionerror 方法,发送输出到控制台。 这些方法中的每一个都会使用合适的ANSI颜色以展示不同的用途。 例如,我们要为用户展示一些常规信息。 通常,info 将会以绿色文本在控制台展示。

/**
 * 执行控制台命令。
 *
 * @return mixed
 */
public function handle()
{
    // ...

    $this->info('The command was successful!');
}

输出错误信息,使用 error 方法。错误信息通常使用红色字体显示:

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

您可以使用line 方法输出无色文本:

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

您可以使用 newLine 方法输出空白行:

// 输出单行空白...
$this->newLine();

// 输出三行空白...
$this->newLine(3);

表格

table 方法使正确格式化多行/多列数据变得容易。你所需要做的就是提供表的列名和数据,Laravel 会自动为你计算适当的表宽和高:

use App\Models\User;

$this->table(
    ['Name', 'Email'],
    User::all(['name', 'email'])->toArray()
);

进度条

对于长时间运行的任务,显示进度栏以告知用户任务的完成情况会很有帮助。使用该 withProgressBar 方法,Laravel 将显示进度条,并在每次迭代中将其进度提前到给定的可迭代值:

use App\Models\User;

$users = $this->withProgressBar(User::all(), function ($user) {
    $this->performTask($user);
});

有时,你可能需要对进度条的高级方式进行更多的手动控制。首先,定义过程将要迭代的步骤总数。然后,在处理完每个项目后前进进度栏:

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

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

$bar->start();

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

    $bar->advance();
}

$bar->finish();

技巧:有关更多高级选项,请查看 Symfony Progress Bar 组件文档

注册命令

你的所有控制台命令都在应用程序的 App\Console\Kernel 类中注册,该类是应用程序的「控制台内核」。在 commands 此类的方法中,你将看到对内核 load 方法的调用。该 load 方法将扫描 app/Console/Commands 目录并自动向Artisan注册其中包含的每个命令。你甚至可以随意调用该 load 方法来扫描其他目录以查找 Artisan 命令:

/**
 * 为应用程序注册命令。
 *
 * @return void
 */
protected function commands()
{
    $this->load(__DIR__.'/Commands');
    $this->load(__DIR__.'/../Domain/Orders/Commands');

    // ...
}

如有必要,你可以通过将命令的类名添加到类的 $commands 属性中来手动注册命令 App\Console\Kernel。当 Artisan 启动时,此属性中列出的所有命令将由 服务容器 解析并向 Artisan 注册:

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

以编程方式执行命令

有时,你可能希望在 CLI 外部执行 Artisan 命令。例如,你可能希望从路线或控制器执行 Artisan 命令。你可以 callArtisan Facade 上使用该方法来完成此操作。call 方法将命令的签名名称或类名称作为其第一个参数,并将命令参数的数组作为第二个参数。退出代码将被返回:

use Illuminate\Support\Facades\Artisan;

Route::post('/user/{user}/mail', function ($user) {
    $exitCode = Artisan::call('mail:send', [
        'user' => $user, '--queue' => 'default'
    ]);

    //
});

或者,您可以将整个 Artisan 命令 call 作为字符串传递给该方法:

Artisan::call('mail:send 1 --queue=default');

传递数组值

如果你的命令定义了一个接受数组的选项,则可以将值数组传递给该选项:

use Illuminate\Support\Facades\Artisan;

Route::post('/mail', function () {
    $exitCode = Artisan::call('mail:send', [
        '--id' => [5, 13]
    ]);
});

传递布尔值

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

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

队列 Artisan 命令

使用 Facade 上的 queue 方法 Artisan,你甚至可以将 Artisan 命令排队,以便 队列工作在后台对其进行处理。使用此方法之前,请确保已配置队列并正在运行队列侦听器:

use Illuminate\Support\Facades\Artisan;

Route::post('/user/{user}/mail', function ($user) {
    Artisan::queue('mail:send', [
        'user' => $user, '--queue' => 'default'
    ]);

    //
});

使用 onConnectiononQueue 方法,你可以指定将 Artisan 命令分派到的连接或队列:

Artisan::queue('mail:send', [
    'user' => 1, '--queue' => 'default'
])->onConnection('redis')->onQueue('commands');

从其他命令调用命令

有时你可能希望从现有的 Artisan 命令中调用其他命令。你可以使用该 call 方法进行操作。call 方法接受命令名称和命令参数/选项的数组:

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

    //
}

如果你想调用另一个控制台命令并禁止其所有输出,则可以使用 callSilently 方法。callSilently 方法具有与方法相同的签名
call

$this->callSilently('mail:send', [
    'user' => 1, '--queue' => 'default'
]);

Stub 定制

Artisan 控制台的 make 命令用于创建各种类,例如控制器,作业,迁移和测试。这些类是使用「stub」文件生成的,这些文件中会根据你的输入填充值。但是,你可能需要对Artisan生成的文件进行少量更改。为此,你可以使用以下 stub:publish 命令将最常见的存根发布到你的应用程序中,以便你可以自定义它们:

php artisan stub:publish

发布的 stub 将存放于您的应用根目录下的 stubs 目录中。对这些 stub 进行任何改动都将在您使用 Artisan make 命令生成相应的类的时候反映出来。

事件

Artisan 运行命令时,三个事件Illuminate\Console\Events\ArtisanStarting, Illuminate\Console\Events\CommandStartingIlluminate\Console\Events\CommandFinishedArtisanStarting Artisan 开始运行时,将立即调度该事件。接下来,在 CommandStarting 命令运行之前立即调度事件。最后, CommandFinished 一旦命令执行完毕,便调度该事件。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/laravel/8.5/art...

译文地址:https://learnku.com/docs/laravel/8.5/art...

上一篇 下一篇
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
贡献者:11
讨论数量: 4
发起讨论 只看当前版本


日景
原来在 Homestead 中 PHP artisan 命令是有个缩写 art
2 个点赞 | 4 个回复 | 分享 | 课程版本 5.7
xumng
页面和command命令行双导入的实现
0 个点赞 | 0 个回复 | 分享 | 课程版本 5.8
小豆
译者署名,点击头像,UI 出现问题!
0 个点赞 | 0 个回复 | 问答 | 课程版本 5.5