跳至內容

Artisan 主控台

簡介

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 (REPL)

Laravel Tinker 是 Laravel 框架的強大 REPL,由 PsySH 套件提供支援。

安裝

所有 Laravel 應用程式預設都包含 Tinker。但是,如果您先前已從應用程式中移除 Tinker,可以使用 Composer 安裝 Tinker

composer require laravel/tinker
lightbulb

想要在使用 Laravel 應用程式時進行熱重新載入、多行程式碼編輯和自動完成嗎?請查看 Tinkerwell

用法

Tinker 允許您在命令列上與整個 Laravel 應用程式互動,包括您的 Eloquent 模型、作業、事件等等。若要進入 Tinker 環境,請執行 tinker Artisan 命令

php artisan tinker

您可以使用 vendor:publish 命令發布 Tinker 的組態檔

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

dispatch 輔助函式和 Dispatchable 類別上的 dispatch 方法依賴垃圾回收機制將作業放入佇列中。因此,當使用 tinker 時,您應該使用 Bus::dispatchQueue::push 來派送作業。

命令允許清單

Tinker 使用「允許」清單來決定允許在其 Shell 內執行哪些 Artisan 命令。依預設,您可以執行 clear-compileddownenvinspiremigratemigrate:installupoptimize 命令。如果您想要允許更多命令,可以將它們新增至 tinker.php 組態檔中的 commands 陣列

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

不應別名的類別

通常,當您在 Tinker 中與類別互動時,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

命令結構

產生命令之後,您應該為類別的 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
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user}';
 
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send a marketing email to a user';
 
/**
* Execute the console command.
*/
public function handle(DripEmailer $drip): void
{
$drip->send(User::find($this->argument('user')));
}
}
lightbulb

為了提高程式碼的重複使用率,最佳實務是保持主控台命令的精簡,並讓它們委派給應用程式服務來完成其任務。在上面的範例中,請注意我們注入了一個服務類別來執行傳送電子郵件的「繁重工作」。

結束代碼

如果沒有從 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;
 
Artisan::command('mail:send {user}', function (DripEmailer $drip, string $user) {
$drip->send(User::find($user));
});

閉包命令描述

在定義基於閉包的命令時,您可以使用 purpose 方法為命令添加描述。當您執行 php artisan listphp artisan help 命令時,將會顯示此描述。

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

可隔離的命令

exclamation

若要使用此功能,您的應用程式必須使用 memcachedredisdynamodbdatabasefilearray 快取驅動程式作為應用程式的預設快取驅動程式。此外,所有伺服器都必須與同一個中央快取伺服器通訊。

有時候,您可能希望確保一次只能執行一個命令實例。若要實現此目的,您可以在您的命令類別上實作 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 方法來自訂此金鑰,允許您將命令的參數或選項整合到金鑰中。

/**
* Get the isolatable ID for the command.
*/
public function isolatableId(): string
{
return $this->argument('user');
}

鎖定過期時間

預設情況下,隔離鎖會在命令完成後過期。或者,如果命令被中斷且無法完成,鎖將在一小時後過期。但是,您可以通過在您的命令上定義 isolationLockExpiresAt 方法來調整鎖定過期時間。

use DateTimeInterface;
use DateInterval;
 
/**
* Determine when an isolation lock expires for the command.
*/
public function isolationLockExpiresAt(): DateTimeInterface|DateInterval
{
return now()->addMinutes(5);
}

定義輸入期望

在編寫控制台命令時,通常會透過參數或選項從使用者收集輸入。Laravel 讓您可以使用命令上的 signature 屬性,非常方便地定義您期望從使用者獲得的輸入。signature 屬性允許您使用單一、表達性強、類似路由的語法,定義命令的名稱、參數和選項。

參數

所有使用者提供的參數和選項都用大括號括起來。在以下範例中,該命令定義了一個必需的參數:user

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user}';

您也可以使參數成為可選的,或者為參數定義預設值。

// Optional argument...
'mail:send {user?}'
 
// Optional argument with default value...
'mail:send {user=foo}'

選項

選項和參數一樣,是使用者輸入的另一種形式。當它們透過命令列提供時,選項會以兩個連字符 (--) 作為前綴。選項有兩種:接收值的選項和不接收值的選項。不接收值的選項充當布林值「開關」。讓我們看看這種類型選項的範例。

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user} {--queue}';

在這個範例中,呼叫 Artisan 命令時可以指定 --queue 開關。如果傳遞了 --queue 開關,則選項的值將為 true。否則,該值將為 false

php artisan mail:send 1 --queue

帶值的選項

接下來,讓我們看看一個需要值的選項。如果使用者必須為選項指定值,您應該在選項名稱後加上 = 符號。

/**
* The name and signature of the console command.
*
* @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 的值設定為一個陣列,其中 12 作為其值。

php artisan mail:send 1 2

* 字元可以與可選的參數定義結合使用,以允許零個或多個參數實例。

'mail:send {user?*}'

選項陣列

在定義期望接收多個輸入值的選項時,傳遞給命令的每個選項值都應以選項名稱作為前綴。

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

可以透過傳遞多個 --id 參數來呼叫此類命令。

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

輸入描述

您可以透過使用冒號將參數名稱與描述分開,為輸入參數和選項指定描述。如果您需要更多空間來定義您的命令,可以將定義分散到多行。

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send
{user : The ID of the user}
{--queue : Whether the job should be queued}';

提示輸入遺失值

如果您的命令包含必需的參數,則在未提供這些參數時,使用者將會收到錯誤訊息。或者,您也可以透過實作 PromptsForMissingInput 介面,將您的命令設定為在缺少必需參數時自動提示使用者。

<?php
 
namespace App\Console\Commands;
 
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
 
class SendEmails extends Command implements PromptsForMissingInput
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user}';
 
// ...
}

如果 Laravel 需要從使用者那邊收集必需的參數,它會透過使用參數名稱或描述智慧地措辭問題,自動向使用者詢問該參數。如果您希望自訂用於收集必需參數的問題,您可以使用 promptForMissingArgumentsUsing 方法,返回一個以參數名稱作為鍵的問題陣列。

/**
* Prompt for missing input arguments using the returned questions.
*
* @return array<string, string>
*/
protected function promptForMissingArgumentsUsing(): array
{
return [
'user' => 'Which user ID should receive the mail?',
];
}

您也可以使用包含問題和佔位符的元組來提供佔位符文字。

return [
'user' => ['Which user ID should receive the mail?', 'E.g. 123'],
];

如果您想完全控制提示,您可以提供一個閉包,該閉包應提示使用者並返回他們的答案。

use App\Models\User;
use function Laravel\Prompts\search;
 
// ...
 
return [
'user' => fn () => search(
label: 'Search for a user:',
placeholder: 'E.g. Taylor Otwell',
options: fn ($value) => strlen($value) > 0
? User::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all()
: []
),
];
lightbulb

完整的 Laravel 提示 文件包含有關可用提示及其用法的更多資訊。

如果您希望提示使用者選擇或輸入選項,您可以在命令的 handle 方法中包含提示。但是,如果您只希望在也自動提示使用者輸入遺失的參數時才提示他們,那麼您可以實作 afterPromptingForMissingArguments 方法。

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use function Laravel\Prompts\confirm;
 
// ...
 
/**
* Perform actions after the user was prompted for missing arguments.
*/
protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output): void
{
$input->setOption('queue', confirm(
label: 'Would you like to queue the mail?',
default: $this->option('queue')
));
}

命令 I/O

擷取輸入

在執行命令時,您可能需要存取命令所接受的參數和選項的值。為此,您可以使用 argumentoption 方法。如果參數或選項不存在,將返回 null

/**
* Execute the console command.
*/
public function handle(): void
{
$userId = $this->argument('user');
}

如果您需要以 array 形式檢索所有參數,請呼叫 arguments 方法。

$arguments = $this->arguments();

可以使用 option 方法輕鬆地檢索選項,就像檢索參數一樣。若要以陣列形式檢索所有選項,請呼叫 options 方法。

// Retrieve a specific option...
$queueName = $this->option('queue');
 
// Retrieve all options as an array...
$options = $this->options();

提示輸入

lightbulb

Laravel 提示是一個 PHP 套件,用於為您的命令列應用程式新增美觀且使用者友善的表單,具有類似瀏覽器的功能,包括佔位符文字和驗證。

除了顯示輸出外,您也可以在命令執行期間要求使用者提供輸入。ask 方法會用給定的問題提示使用者,接受他們的輸入,然後將使用者的輸入返回給您的命令。

/**
* Execute the console command.
*/
public function handle(): void
{
$name = $this->ask('What is your name?');
 
// ...
}

ask 方法也接受可選的第二個參數,該參數指定如果未提供使用者輸入時應返回的預設值。

$name = $this->ask('What is your name?', 'Taylor');

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 (string $input) {
// Return auto-completion options...
});

多項選擇題

如果您需要在詢問問題時向使用者提供預先定義的選擇集,您可以使用 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
);

寫入輸出

若要將輸出傳送到控制台,您可以使用 lineinfocommentquestionwarnerror 方法。這些方法中的每一個都會針對其用途使用適當的 ANSI 顏色。例如,讓我們向使用者顯示一些一般資訊。通常,info 方法會在控制台中顯示為綠色文字。

/**
* Execute the console command.
*/
public function handle(): void
{
// ...
 
$this->info('The command was successful!');
}

若要顯示錯誤訊息,請使用 error 方法。錯誤訊息文字通常以紅色顯示。

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

您可以使用 line 方法顯示純粹、無顏色的文字。

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

您可以使用 newLine 方法顯示空白行。

// Write a single blank line...
$this->newLine();
 
// Write three blank lines...
$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();
lightbulb

如需更多進階選項,請查看 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 facade 上的 call 方法來完成此操作。call 方法接受命令的簽名名稱或類別名稱作為其第一個參數,並接受命令參數陣列作為第二個參數。將返回退出碼。

use Illuminate\Support\Facades\Artisan;
 
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;
 
Route::post('/mail', function () {
$exitCode = Artisan::call('mail:send', [
'--id' => [5, 13]
]);
});

傳遞布林值

如果您需要指定不接受字串值的選項值,例如 migrate:refresh 命令的 --force 旗標,您應該傳遞 truefalse 作為選項的值。

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

佇列 Artisan 命令

透過在 Artisan 外觀上使用 queue 方法,您甚至可以將 Artisan 命令加入佇列,以便讓您的佇列工作者在背景處理。在使用此方法之前,請確保您已設定好佇列並正在執行佇列監聽器。

use Illuminate\Support\Facades\Artisan;
 
Route::post('/user/{user}/mail', function (string $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 方法接受命令名稱和命令參數/選項的陣列。

/**
* Execute the console command.
*/
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 方法。

/**
* Execute the console command.
*/
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
});

Stub 自訂

Artisan 控制台的 make 命令用於建立各種類別,例如控制器、任務、遷移和測試。這些類別是使用「stub」檔案產生的,這些檔案會根據您的輸入填入值。但是,您可能希望對 Artisan 產生的檔案進行小幅更改。為了實現這一點,您可以使用 stub:publish 命令將最常見的 stub 發佈到您的應用程式中,以便您可以自訂它們。

php artisan stub:publish

發佈的 stub 將位於應用程式根目錄下的 stubs 目錄中。當您使用 Artisan 的 make 命令產生其對應的類別時,您對這些 stub 所做的任何變更都會反映出來。

事件

Artisan 在執行命令時會發送三個事件:Illuminate\Console\Events\ArtisanStartingIlluminate\Console\Events\CommandStartingIlluminate\Console\Events\CommandFinished。當 Artisan 開始執行時,會立即發送 ArtisanStarting 事件。接下來,會在命令執行之前立即發送 CommandStarting 事件。最後,會在命令執行完成後發送 CommandFinished 事件。