简介

Artisan 是 Laravel 自带的命令行界面。Artisan 以 artisan 脚本的形式存在于应用程序的根目录中,它提供了一系列实用的命令,你可以在构建应用程序时使用。若要查看所有可用的 Artisan 命令列表,可以使用 list 命令:

php artisan list

每个命令还包含一个“帮助”界面,用于显示并描述该命令可用的参数和选项。若要查看帮助界面,可在命令名称前加上 help:

php artisan help migrate

Laravel Sail

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

./vendor/bin/sail artisan list

Tinker(交互式解释器)

Laravel Tinker 是 Laravel 框架的一个功能强大的交互式解释器(REPL),由 PsySH 包提供支持。

安装

所有 Laravel 应用程序默认都包含 Tinker。不过,如果你之前从应用程序中移除了 Tinker,也可以通过 Composer 来安装:

composer require laravel/tinker

想在与 Laravel 应用程序交互时获得热重载、多行代码编辑和自动补全功能?不妨试试 Tinkerwell!

用法

借助 Tinker,你可以在命令行中与整个 Laravel 应用程序进行交互,包括 Eloquent 模型、作业、事件等等。若要进入 Tinker 环境,运行 tinker Artisan 命令即可:

php artisan tinker

你可以使用 vendor:publish 命令发布 Tinker 的配置文件:

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

dispatch 辅助函数以及 Dispatchable 类中的 dispatch 方法依赖垃圾回收来将作业放入队列。因此,在使用 Tinker 时,你应该使用 Bus::dispatch 或 Queue::push 来分发作业。

命令允许列表

Tinker 利用一个“允许”列表来确定哪些 Artisan 命令允许在其 shell 中运行。默认情况下,你可以运行 clear-compiled、down、env、inspire、migrate、migrate:install、up 和 optimize 命令。如果你想要允许更多命令,可以将它们添加到 tinker.php 配置文件中的 commands 数组里:

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

不应设置别名的类

通常情况下,Tinker 会在你与类进行交互时自动为这些类设置别名。不过,你可能希望某些类永远不设置别名。你可以通过在 tinker.php 配置文件的 dont_alias 数组中列出这些类来实现这一点:

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

编写命令

除了 Artisan 自带的命令之外,你还可以创建自己的自定义命令。命令通常存储在 app/Console/Commands 目录中;不过,只要你指示 Laravel 扫描其他目录中的 Artisan 命令,你也可以自由选择存储位置。

生成命令

若要创建新命令,可以使用 make:command Artisan 命令。该命令会在 app/Console/Commands 目录中创建一个新的命令类。如果应用程序中不存在该目录,也不必担心——在你首次运行 make:command Artisan 命令时,该目录会被自动创建:

php artisan make:command SendEmails

命令结构

生成命令后,你应该使用 Signature 和 Description 属性来定义命令的签名和描述。Signature 属性还允许你定义命令的输入要求。当命令被执行时,会调用 handle 方法。你可以将命令的逻辑放置在该方法中。

下面来看一个命令示例。请注意,我们可以通过命令的 handle 方法请求所需的任何依赖项。Laravel 服务容器 会自动注入该方法签名中类型提示的所有依赖项:

<?php

namespace App\Console\Commands;

use App\Models\User;
use App\Support\DripEmailer;
use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
use Illuminate\Console\Command;

#[Signature('mail:send {user}')]
#[Description('Send a marketing email to a user')]
class SendEmails extends Command
{
    /**
     * Execute the console command.
     */
    public function handle(DripEmailer $drip): void
    {
        $drip->send(User::find($this->argument('user')));
    }
}

为了提高代码复用性,让控制台命令保持轻量,并让它们将任务委托给应用程序服务来完成,这是一种良好实践。在上面的示例中,请注意我们注入了一个服务类来完成发送电子邮件的“繁重工作”。

退出码

如果 handle 方法没有返回任何内容,且命令执行成功,命令将以 0 作为退出码退出,表示成功。不过,handle 方法也可以选择返回一个整数,来手动指定命令的退出码:

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

return 1;

如果你想从命令中的任意方法中使命令“失败”,可以使用 fail 方法。fail 方法会立即终止命令的执行,并返回 1 作为退出码:

$this->fail('Something went wrong.');

闭包命令

基于闭包的命令为定义控制台命令提供了一种替代方式,无需将命令定义为类。就像路由闭包是控制器的替代方案一样,你可以把命令闭包看作是命令类的替代方案。

尽管 routes/console.php 文件并不定义 HTTP 路由,但它定义了基于控制台的应用程序入口点(路由)。在这个文件中,你可以使用 Artisan::command 方法来定义所有基于闭包的控制台命令。command 方法接收两个参数:命令签名和一个闭包,该闭包会接收命令的参数和选项:

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

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

依赖项的类型提示

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

use App\Models\User;
use App\Support\DripEmailer;
use Illuminate\Support\Facades\Artisan;

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

闭包命令描述

在定义基于闭包的命令时,你可以使用 purpose 方法为命令添加描述。当运行 php artisan list 或 php artisan help 命令时,该描述将会显示出来:

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

可隔离命令

若要使用此功能,你的应用程序必须使用 memcached、redis、dynamodb、database、file 或 array 作为应用程序的默认缓存驱动。此外,所有服务器都必须与同一个中央缓存服务器进行通信。

有时你可能希望确保同一时间只能运行一个命令实例。要实现这一点,你可以在命令类上实现 Illuminate\Contracts\Console\Isolatable 接口:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Isolatable;

class SendEmails extends Command implements Isolatable
{
    // ...
}

当你将某个命令标记为 Isolatable 时,Laravel 会自动为该命令启用 --isolated 选项,无需在命令的选项中显式定义它。当使用该选项调用命令时,Laravel 会确保没有其他该命令的实例在运行。Laravel 会尝试使用应用程序的默认缓存驱动来获取一个原子锁,从而实现这一点。如果该命令的其他实例正在运行,该命令将不会执行;不过,该命令仍会以成功的退出状态码退出:

php artisan mail:send 1 --isolated

如果你想指定命令在无法执行时应返回的退出状态码,可以通过 isolated 选项提供所需的状态码:

php artisan mail:send 1 --isolated=12

锁 ID

默认情况下,Laravel 会使用命令名称来生成用于在应用程序缓存中获取原子锁的字符串键。不过,你可以在 Artisan 命令类中定义 isolatableId 方法来自定义该键,从而将命令的参数或选项整合到键中:

/**
 * 获取命令的可隔离 ID。
 */
public function isolatableId(): string
{
    return $this->argument('user');
}

锁过期时间

默认情况下,隔离锁会在命令执行完毕后过期。或者,如果命令被中断且无法完成,该锁将在一小时后过期。不过,你可以在命令中定义 isolationLockExpiresAt 方法来调整锁的过期时间:

use DateTimeInterface;
use DateInterval;

/**
 * 确定命令的隔离锁何时过期。
 */
public function isolationLockExpiresAt(): DateTimeInterface|DateInterval
{
    return now()->plus(minutes: 5);
}

定义输入预期

编写控制台命令时,通常需要通过参数或选项从用户处收集输入。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=}'

在终端中调用命令时,选项快捷键应以单个连字符作为前缀,并且在为选项指定值时,不应包含 = 字符:

php artisan mail:send 1 -Qdefault

输入数组

如果你想定义可接收多个输入值的参数或选项,可以使用 * 字符。首先,让我们看一个指定此类参数的示例:

'mail:send {user*}'

运行此命令时,user 参数可以按顺序传递到命令行。例如,以下命令会将 user 的值设置为一个数组,该数组包含 1 和 2 作为其值:

php artisan mail:send 1 2

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

'mail:send {user?*}'

选项数组

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

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

可以通过传递多个 --id 参数来调用此类命令:

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

输入描述

你可以使用冒号将参数名与描述分隔开,从而为输入参数和选项分配描述。如果需要更多空间来定义命令,可以随时将定义拆分为多行:

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

提示缺失的输入

如果你的命令包含必填参数,当用户未提供这些参数时,将收到一条错误消息。此外,你可以通过实现 PromptsForMissingInput 接口,配置命令在缺少必填参数时自动提示用户:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;

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

    // ...
}

如果 Laravel 需要从用户处收集必填参数,它会自动向用户询问该参数,并利用参数名或描述,智能地组织问题表述。如果你想自定义用于收集必填参数的问题,可以实现 promptForMissingArgumentsUsing 方法,返回一个以参数名为键的问题数组:

/**
 * 使用返回的问题提示缺失的输入参数。
 *
 * @return array<string, string>
 */
protected function promptForMissingArgumentsUsing(): array
{
    return [
        'user' => '应接收邮件的用户 ID 是多少?',
    ];
}

你也可以使用包含问题和占位符的元组,来提供占位文本:

return [
    'user' => ['应接收邮件的用户 ID 是多少?', '例如 123'],
];

如果你希望完全掌控提示,可以提供一个闭包,该闭包用于提示用户并返回用户的回答:

use App\Models\User;
use function Laravel\Prompts\search;

// ...

return [
    'user' => fn () => search(
        label: '搜索用户:',
        placeholder: '例如 Taylor Otwell',
        options: fn ($value) => strlen($value) > 0
            ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
            : []
    ),
];

全面的 Laravel Prompts 文档包含了关于可用提示及其使用方法的更多信息。

如果你想提示用户选择或输入选项,可以在命令的 handle 方法中加入提示。不过,如果你仅希望在用户已被自动提示输入缺失参数时,才提示用户,那么可以实现 afterPromptingForMissingArguments 方法:

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use function Laravel\Prompts\confirm;

// ...

/**
 * 在提示用户输入缺失参数后执行操作。
 */
protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output): void
{
    $input->setOption('queue', confirm(
        label: '是否要将邮件加入队列?',
        default: $this->option('queue')
    ));
}

命令的输入与输出

获取输入

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

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

如果你需要以 array 的形式获取所有参数,请调用 arguments 方法:

$arguments = $this->arguments();

使用 option 方法可以像获取参数一样轻松获取选项。若要以数组形式获取所有选项,请调用 options 方法:

// 获取指定选项...
$queueName = $this->option('queue');

// 以数组形式获取所有选项...
$options = $this->options();

你可以使用 input 方法,以 Illuminate\Console\CommandInput 实例的形式获取命令的参数和选项,该实例提供了与 HTTP 请求及其他数据容器相同的类型化访问器:

use App\Enums\ReportType;

/**
 * 执行控制台命令。
 */
public function handle(): void
{
    $input = $this->input()->date('from');

    // ...
}

input 方法也可用于从参数或选项中获取单个输入值:

$queue = $this->input('queue', 'default');

提示输入

Laravel Prompts 是一个 PHP 包,可为你的命令行应用添加美观且用户友好的表单,具备类似浏览器的功能,包括占位文本和验证。

除了显示输出,在命令执行期间,你也可以让用户提供输入。ask 方法将向用户提示给定问题,接收其输入,然后将用户输入返回给你的命令:

/**
 * 执行控制台命令。
 */
public function handle(): void
{
    $name = $this->ask('你的名字是什么?');

    // ...
}

ask 方法还接受一个可选的第二个参数,该参数指定当用户未提供输入时应返回的默认值:

$name = $this->ask('你的名字是什么?', 'Taylor');

secret 方法类似于 ask,但用户在控制台中输入时,其输入不会显示。当询问密码等敏感信息时,此方法非常有用:

$password = $this->secret('密码是什么?');

请求确认

如果你需要让用户进行简单的“是/否”确认,可以使用 confirm 方法。默认情况下,该方法会返回 false。但是,如果用户在响应提示时输入 y 或 yes,该方法将返回 true。

if ($this->confirm('是否希望继续?')) {
    // ...
}

如有必要,你可以通过将 true 作为第二个参数传递给 confirm 方法,来指定确认提示默认应返回 true:

if ($this->confirm('是否希望继续?', true)) {
    // ...
}

自动补全

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

$name = $this->anticipate('你的名字是什么?', ['Taylor', 'Dayle']);

或者,你也可以将闭包作为第二个参数传递给 anticipate 方法。每次用户输入一个字符时,都会调用该闭包。该闭包应接受一个字符串参数(包含用户到目前为止的输入),并返回用于自动补全的选项数组:

use App\Models\Address;

$name = $this->anticipate('你的地址是什么?', function (string $input) {
    return Address::whereLike('name', "{$input}%")
        ->limit(5)
        ->pluck('name')
        ->all();
});

多选问题

当你向用户提问时,如果需要提供一组预定义的选项,可以使用 choice 方法。你可以通过将索引作为第三个参数传递给该方法,来设置未选择任何选项时返回的默认值的数组索引:

$name = $this->choice(
    '你的名字是什么?',
    ['Taylor', 'Dayle'],
    $defaultIndex
);

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

$name = $this->choice(
    '你的名字是什么?',
    ['Taylor', 'Dayle'],
    $defaultIndex,
    $maxAttempts = null,
    $allowMultipleSelections = false
);

写入输出

若要向控制台发送输出,可以使用 line、newLine、info、comment、question、warn、alert 和 error 方法。这些方法都会根据自身用途使用合适的 ANSI 颜色。例如,我们来向用户显示一些常规信息。通常,info 方法会在控制台中以绿色文本显示:

/**
 * 执行控制台命令。
 */
public function handle(): void
{
    // ...

    $this->info('命令执行成功!');
}

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

$this->error('出现错误!');

你可以使用 line 方法显示纯文本,无颜色:

$this->line('在屏幕上显示此内容');

你可以使用 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 $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 进度条组件文档。

注册命令

默认情况下,Laravel 会自动注册 app/Console/Commands 目录中的所有命令。不过,你可以使用应用的 bootstrap/app.php 文件中的 withCommands 方法,指示 Laravel 扫描其他目录以查找 Artisan 命令:

->withCommands([
    __DIR__.'/../app/Domain/Orders/Commands',
])

如有必要,你也可以将命令的类名提供给 withCommands 方法,手动注册命令:

use App\Domain\Orders\Commands\SendEmails;

->withCommands([
    SendEmails::class,
])

当 Artisan 启动时,应用中的所有命令都会被服务容器解析,并注册到 Artisan 中。

以编程方式执行命令

有时你可能希望在命令行界面(CLI)之外执行 Artisan 命令。例如,你可能希望从路由或控制器中执行 Artisan 命令。你可以使用 Artisan 门面上的 call 方法来实现这一点。call 方法的第一个参数接受命令的签名名称或类名,第二个参数接受一个命令参数数组。该方法会返回退出码:

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Route;

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

    // ...
});

此外,你也可以将整个 Artisan 命令以字符串的形式传递给 call 方法:

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

传递数组值

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

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Route;

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

传递布尔值

如果你需要为不接受字符串值的选项指定值,例如 migrate:refresh 命令上的 --force 标志,你应该将 true 或 false 作为该选项的值传入:

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

将 Artisan 命令加入队列

通过使用 Artisan 门面上的 queue 方法,你甚至可以将 Artisan 命令加入队列,以便由你的 队列工作进程 在后台进行处理。在使用此方法之前,请确保你已经配置好队列,并且正在运行队列监听器:

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Route;

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

    // ...
});

通过使用 onConnection 和 onQueue 方法,你可以指定该 Artisan 命令应分发到的连接或队列:

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

从其他命令中调用命令

有时你可能希望从现有的 Artisan 命令中调用其他命令。你可以使用 call 方法来实现这一点。此 call 方法接受命令名称以及一个命令参数 / 选项数组:

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

    // ...
}

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

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

信号处理

如你所知,操作系统可以向正在运行的进程发送信号。例如,SIGTERM 信号是操作系统用来请求程序优雅终止的方式。如果你希望在 Artisan 控制台命令中监听信号,并在信号触发时执行代码,可以使用 trap 方法:

/**
 * 执行控制台命令。
 */
public function handle(): void
{
    $this->trap(SIGTERM, fn () => $this->shouldKeepRunning = false);

    while ($this->shouldKeepRunning) {
        // ...
    }
}

要同时监听多个信号,你可以向 trap 方法传入一个信号数组:

$this->trap([SIGTERM, SIGQUIT], function (int $signal) {
    $this->shouldKeepRunning = false;

    dump($signal); // SIGTERM / SIGQUIT
});

dev 命令

dev Artisan 命令可在单个终端窗口中启动本地开发所需的所有进程。默认情况下,它会并发运行 PHP 开发服务器、队列工作进程、通过 Pail 进行日志跟踪,以及 Vite 资源编译:

php artisan dev

在底层,dev 命令使用 @laravel/multiplex npm 包来管理进程,为每个进程分配一个带有可搜索、可滚动输出的独立标签页。每个进程都有标签和颜色标识,方便你轻松区分。如果某个进程崩溃,它会自动重启;当你退出时,所有输出都会回写到你的终端,确保信息不会丢失。

dev 命令需要 Node 22.13 或更高版本。在 Windows 系统上,它会回退到 concurrently npm 包,且不提供标签页界面。

默认进程如下:

名称命令
serverphp artisan serve
queuephp artisan queue:listen --tries=1 --timeout=0
logsphp artisan pail --timeout=0
vitenpm run dev

vite 进程会自动检测你使用的 Node 包管理器(npm、pnpm、Yarn 或 Bun),并调用相应的运行命令。

自定义 dev 进程

你可以通过使用 DevCommands 类(通常在应用程序的 AppServiceProvider 的 boot 方法中)来自定义 dev 命令运行的进程。register 方法接受一个命令字符串和一个可选的名称:

use Illuminate\Foundation\DevCommands;

/**
 * 引导任何应用程序服务。
 */
public function boot(): void
{
    DevCommands::register('some-command --flag', 'my-process');
}

注册 Artisan 命令时,可以使用 artisan 方法,该方法会自动为命令添加 php artisan 前缀:

DevCommands::artisan('horizon', 'horizon');

同样,node 方法会为命令添加检测到的包管理器的运行命令前缀(例如 npm run),而 nodeExec 方法会为命令添加包管理器的执行命令前缀(例如 npx):

DevCommands::node('storybook', 'storybook');

DevCommands::nodeExec('tailwindcss -i resources/css/app.css -o public/css/app.css --watch', 'tailwind');

如果你注册的进程名称与默认进程相同,那么你注册的进程会替代默认进程。例如,你可以自定义服务器进程,使其使用不同的端口:

DevCommands::artisan('serve --host=localhost --port=9000', 'server');

你还可以自定义终端中进程标签的颜色。可用的颜色方法有 blue、purple、pink、orange、green 和 yellow。你也可以向 color 方法传入自定义的十六进制颜色值:

DevCommands::register('my-command', 'my-process')->green();

DevCommands::register('my-command', 'my-process')->color('#ff6347');

若要在不启动进程的情况下查看所有已注册的开发进程,请使用 dev:list 命令:

php artisan dev:list

重启失败的进程

如果某个进程崩溃,Laravel 会在短暂延迟后重启它,最多重启五次,之后会将其标记为失败。若进程在启动后一秒内就终止,则不会重启,因为它很可能从一开始就未能成功启动。使用 r 手动重启进程会重置计数器。

你可以使用 --no-restart 选项在单次运行中禁用此行为:

php artisan dev --no-restart

或者,你可以使用 disableAutoRestart 方法为整个应用程序禁用此行为:

DevCommands::disableAutoRestart();

筛选 dev 进程

你可以使用 only 方法指示 dev 命令,使其在被调用时仅运行指定的进程。类似地,你也可以使用 except 方法排除指定的进程:

// 仅运行 server 和 vite 进程...
DevCommands::only('server', 'vite');

// 运行除队列工作进程之外的所有进程...
DevCommands::except('queue');

你可以使用 withoutVendorCommands 和 withoutDefaultCommands 方法,排除由包注册的命令或 Laravel 的默认命令:

DevCommands::withoutVendorCommands();

DevCommands::withoutDefaultCommands();

桩文件自定义

Artisan 控制台的 make 命令用于创建各类类,例如控制器、任务、迁移和测试。这些类是通过“存根”文件生成的,这些文件会根据输入值进行填充。不过,你可能希望对 Artisan 生成的文件进行一些小的修改。为此,你可以使用 stub:publish 命令,将最常用的存根发布到你的应用程序中,以便对其进行自定义:

php artisan stub:publish

发布的存根将位于应用程序根目录下的 stubs 目录中。当你使用 Artisan 的 make 命令生成对应的类时,对这些存根所做的任何修改都会体现出来。

事件

Artisan 在执行命令时会触发三个事件:Illuminate\Console\Events\ArtisanStarting、Illuminate\Console\Events\CommandStarting 和 Illuminate\Console\Events\CommandFinished。ArtisanStarting 事件在 Artisan 开始运行时立即触发。接着,CommandStarting 事件会在命令执行前立即触发。最后,当命令执行完成时,CommandFinished 事件触发。