Artisan 命令行
介绍
Artisan 是 Laravel 中自带的命令行接口。Artisan 以 artisan
脚本的方式存在于应用的根目录中,提供了许多有用的命令,帮助开发者创建应用。使用 list
命令可以查看所有可用的Artisan 命令:
php artisan list
每个命令都与 "help" 帮助界面,它能显示和描述该命令可用的参数和选项。要查看帮助界面,请在命令前加上 help
即可:
php artisan help migrate
Laravel Sail
如果你使用 Laravel Sail 作为本地开发环境,记得使用 sail
命令行来调用 Artisan 命令。Sail 会在应用的 Docker容器中执行 Artisan 命令:
./vendor/bin/sail artisan list
Tinker (REPL)
Laravel Tinker 是为 Laravel 提供的强大的 REPL(交互式解释器),由 PsySH(https://github.com/bobthecow/psysh) 驱动支持。
安装
所有的 Laravel 应用默认都自带 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::dispath
或 Queue::push
来分发任务。
命令白名单
Tinker 使用白名单来确定哪些 Artisan 命令可以在其 Shell 中运行。默认情 况下,你可以运行 clear-compiled
、down
、env
、inspire
、migrate
、optimize
和 up
命令。如果你想允许更多命令,你可以将它们添加到 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
Artisan 命令的时候自动创建:
php artisan make:command SendEmails
命令结构
生成命令后,应该为该类的 signature
和 description
属性设置设当的值。当在 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';
/**
* 执行命令
*/
public function handle(DripEmailer $drip): void
{
$drip->send(User::find($this->argument('user')));
}
}
为了更好地复用代码,请尽量让你的命令类保持轻量并且能够延迟到应用服务中完成。上例中,我们注入了一个服务类来进行发送电子邮件的「繁重工作」。
闭包命令
基于闭包的命令为将控制台命令定义为类提供了一种替代方法。与路由闭包可以替代控制器一样,可以将命令闭包视为命令类的替代。在 app/Console/Kernel.php
文件的 commands
方法中 ,Laravel 加载 routes/console.php
文件:
/**
* 注册闭包命令
*/
protected function commands(): void
{
require base_path('routes/console.php');
}
尽管该文件没有定义 HTTP 路由,但它定义了进入应用程序的基于控制台的入口 (routes) 。在这个文件中,你可以使用 Artisan::command
方法定义所有的闭包路由。 command
方法接受两个参数: 命令名称 和可调用的闭包,闭包接收命令的参数和选项:
Artisan::command('mail:send {user}', function (string $user) {
$this->info("Sending email to: {$user}!");
});
该闭包绑定到基础命令实例,因此你可以完全访问通常可以在完整命令类上访问的所有辅助方法。
Type-Hinting Dependencies
除了接受命令参数及选项外,命令闭包也可以使用类型约束从 服务容器 中解析其他的依赖关系:
use App\Models\User;
use App\Support\DripEmailer;
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
原子锁到期时间
默认情况下,单例锁会在命令完成后过期。或者如果命令被打断且无法完成的话,锁会在一小时后过期。不过你也可以通过定义命令的 isolationLockExpiresAt
方法来调整过期时间:
use DateTimeInterface;
use DateInterval;
/**
* 定义单例锁的到期时间
*/
public function isolationLockExpiresAt(): DateTimeInterface|DateInterval
{
return now()->addMinutes(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
的值为 foo
和 bar
:
php artisan mail:send 1 2
*
字符可以与可选的参数结合使用,允许您定义零个或多个参数实例:
'mail:send {user?*}'
选项数组
当定义需要多个输入值的选项时,传递给命令的每个选项值都应以选项名称作为前缀:
'mail:send {--id=*}'
这样的命令可以通过传递多个 --id
参数来调用:
php artisan mail:send --id=1 --id=2