Artisan 主控台
簡介
Artisan 是 Laravel 內所包含的指令列界面。Artisan 是放在專案根目錄的 artisan
工序指令,提供多種實用指令來幫你撰寫你的專案。若要檢視所有可用的 Artisan 指令,可以使用 list
指令:
1php artisan list
1php artisan list
每個指令也包含了一個「help」畫面,用於顯示指令的說明以及可用的引數與選項。若要檢視輔助說明畫面,請在指令名稱的前面加上 help
:
1php artisan help migrate
1php artisan help migrate
Laravel Sail
若使用 Laravel Sail 作為本機開發環境,請記得使用 sail
指令列來叫用 Artisan 指令。Sail 會在專案的 Docker 容器內執行 Artisan 指令。
1./sail artisan list
1./sail artisan list
Tinker (REPL)
Laravel Tinker 是用於 Laravel 框架的強大 REPL,由 PsySH 套件提供。
安裝
所有的 Laravel 專案預設都包含了 Tinker。但若先前曾自專案內移除 Tinker,則可使用 Composer 來安裝:
1composer require laravel/tinker
1composer require laravel/tinker
想找個能與你的 Laravel 應用程式互動的圖形化 UI 嗎?試試 Tinkerwell 吧!
使用
Tinker 可讓你在指令列內與完整的 Laravel 專案進行互動,包含 Eloquent Model、任務、事件…等。要進入 Tinker 環境,請執行 tinker
Artisan 指令:
1php artisan tinker
1php artisan tinker
可以通過 vendor:publish
指令來安裝 Tinker 的設定檔:
1php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"
1php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"
dispatch
輔助函式與 Dispatchable
類別上的 dispatch
方法需要仰賴垃圾回收機制來將任務放進佇列中。因此,在使用 Tinker 時,應使用 Bus::dispatch
或 Queue::push
來分派任務。
指令允許列表
Tinker 使用一個「allow」清單來判斷哪些 Artisan 指令可在其 Shell 內執行。預設情況下,可以執行 clear-compiled
, down
, env
, inspire
, migrate
, optimize
以及 up
指令。若想允許更多指令,可以將要允許的指令加在 tinker.php
設定檔中的 commands
陣列內:
1'commands' => [2 // App\Console\Commands\ExampleCommand::class,3],
1'commands' => [2 // App\Console\Commands\ExampleCommand::class,3],
不應以別名使用的類別
一般來說,Tinker 會在使用過程中自動為類別加上別名。但有些類別可能不希望被設定別名。可以通過在 tinker.php
設定檔中的 dont_alias
陣列中列出這些不想被自動別名的類別來達成:
1'dont_alias' => [2 App\Models\User::class,3],
1'dont_alias' => [2 App\Models\User::class,3],
撰寫指令
除了 Artisan 提供的指令外,也可以建制自己的自訂指令。指令通常儲存於 app/Console/Commands
目錄內。但是,只要你的自訂指令可以被 Composer 載入,也可以自行選擇儲存位置。
產生指令
若要建立新指令,可以使用 make:command
Artisan 指令。該指令會在 app/Console/Commands
目錄下建立一個新的指令類別。若你的專案中沒有這個資料夾,請別擔心——第一次執行 make:command
Artisan 指令的時候會自動建立該資料夾:
1php artisan make:command SendEmails
1php artisan make:command SendEmails
指令結構
產生指令後,應為類別的 signature
與 description
屬性定義適當的值。當在 list
畫面內顯示該指令時,就會用到這些屬性。signature
屬性可以用來定義 指令預期的輸入。handle
方法會在執行該指令時呼叫。可以將指令的邏輯放在該方法內。
來看看一個範例指令。請注意,我們可以通過指令的 handle
方法來要求任意的相依性。Laravel 的 Service Container 會自動插入所有在方法簽章內有型別提示的相依性。
1<?php23namespace App\Console\Commands;45use App\Models\User;6use App\Support\DripEmailer;7use Illuminate\Console\Command;89class SendEmails extends Command10{11 /**12 * The name and signature of the console command.13 *14 * @var string15 */16 protected $signature = 'mail:send {user}';1718 /**19 * The console command description.20 *21 * @var string22 */23 protected $description = 'Send a marketing email to a user';2425 /**26 * Create a new command instance.27 *28 * @return void29 */30 public function __construct()31 {32 parent::__construct();33 }3435 /**36 * Execute the console command.37 *38 * @param \App\Support\DripEmailer $drip39 * @return mixed40 */41 public function handle(DripEmailer $drip)42 {43 $drip->send(User::find($this->argument('user')));44 }45}
1<?php23namespace App\Console\Commands;45use App\Models\User;6use App\Support\DripEmailer;7use Illuminate\Console\Command;89class SendEmails extends Command10{11 /**12 * The name and signature of the console command.13 *14 * @var string15 */16 protected $signature = 'mail:send {user}';1718 /**19 * The console command description.20 *21 * @var string22 */23 protected $description = 'Send a marketing email to a user';2425 /**26 * Create a new command instance.27 *28 * @return void29 */30 public function __construct()31 {32 parent::__construct();33 }3435 /**36 * Execute the console command.37 *38 * @param \App\Support\DripEmailer $drip39 * @return mixed40 */41 public function handle(DripEmailer $drip)42 {43 $drip->send(User::find($this->argument('user')));44 }45}
為了提升程式碼重複使用率,最好保持主控台指令精簡,並將指令的任務委託給應用程式服務來完成。在上方的例子中,可以注意到我們插入了一個服務類別來處理寄送 E-Mail 的這個「重責大任」。
閉包指令
基於閉包的指令提供了以類別定義主控台指令外的另一個選擇。就如同使用閉包來定義路由可用來代替控制器一樣,可以將指令閉包想象成是指令類別的代替。在 app/Console/Kernel.php
檔中的 commands
方法內,Laravel 載入了 routes/console.php
檔:
1/**2 * Register the closure based commands for the application.3 *4 * @return void5 */6protected function commands()7{8 require base_path('routes/console.php');9}
1/**2 * Register the closure based commands for the application.3 *4 * @return void5 */6protected function commands()7{8 require base_path('routes/console.php');9}
這個檔案並沒有定義 HTTP 路由,而是定義從主控台「路由」進入專案的進入點。在該檔案內,可以通過 Artisan::command
方法來定義基於閉包的主控台指令。command
方法接受 2 個引數:指令簽章,以及一個用來接收指令引數與選項的閉包:
1Artisan::command('mail:send {user}', function ($user) {2 $this->info("Sending email to: {$user}!");3});
1Artisan::command('mail:send {user}', function ($user) {2 $this->info("Sending email to: {$user}!");3});
這裡的閉包有綁定到該指令的基礎類別執行個體,因此可以像在完整的指令類別內一樣存取所有的輔助函式。
對相依關係進行型別提示
除了接收指令的引數與選項外,指令閉包也可以通過型別提示來向 Service Container 解析額外的相依關係。
1use App\Models\User;2use App\Support\DripEmailer;34Artisan::command('mail:send {user}', function (DripEmailer $drip, $user) {5 $drip->send(User::find($user));6});
1use App\Models\User;2use App\Support\DripEmailer;34Artisan::command('mail:send {user}', function (DripEmailer $drip, $user) {5 $drip->send(User::find($user));6});
閉包指令描述
在定義基於閉包的指令時,可以使用 purpose
方法來為該指令加上描述。這段描述會在執行 php artisan list
或 php artisan help
指令時顯示:
1Artisan::command('mail:send {user}', function ($user) {2 // ...3})->purpose('Send a marketing email to a user');
1Artisan::command('mail:send {user}', function ($user) {2 // ...3})->purpose('Send a marketing email to a user');
定義預期的輸入
在撰寫主控台指令時,常常會通過引數或選項來向使用者取得輸入。Laravel 通過指令的 signature
屬性來定義預期從使用者那取得的輸入,讓這個過程變得非常簡單。通過 signature
屬性,就能通過類似路由的格式來一次定義名稱、引數,以及選項。非常簡潔有力。
引數
所有由使用者提供的引數與選項都以大括號來包裝。在下列範例中的指令定義了一個必要的引數:user
:
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send {user}';
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send {user}';
也可以將引數設為可選,或是定義引數的預設值:
1// 可選的引數...2mail:send {user?}34// 有預設值的可選引數...5mail:send {user=foo}
1// 可選的引數...2mail:send {user?}34// 有預設值的可選引數...5mail:send {user=foo}
選項
選項就像引數一樣,是另一種形式的使用者輸入。選項在從指令列提供時,會加上兩個減號 (--
) 作為前綴。有兩種類型的選項:一種可接收值,一種沒有接收值。沒有接收值的選項是一種布林「開關」功能。來看看一個使用這種類型選項的例子:
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send {user} {--queue}';
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send {user} {--queue}';
在這個例子中,呼叫該 Artisan 指令時可以指定 --queue
開關。若有傳入 --queue
開關,則該選項的值會是 true
。否則,該值為 false
:
1php artisan mail:send 1 --queue
1php artisan mail:send 1 --queue
帶值的選項
接下來,來看看有值的選項。若使用者必須為選項指定一個值,則應在選項名稱後方加上 =
符號:
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send {user} {--queue=}';
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send {user} {--queue=}';
在這個例子中,使用者可以傳入像這樣給選項帶入一個值。若在叫用該指令時未指定該選項,則其值為 null
:
1php artisan mail:send 1 --queue=default
1php artisan mail:send 1 --queue=default
可以通過在選項名稱後方加上預設值來為選項指派一個預設值。若使用者未傳入選項值,將會使用預設值:
1mail:send {user} {--queue=default}
1mail:send {user} {--queue=default}
選項捷徑
若要在定義選項時指定捷徑,可以在選項名稱前加上其捷徑名稱,並使用 |
字元來區分捷徑名稱與完整的選項名稱:
1mail:send {user} {--Q|queue}
1mail:send {user} {--Q|queue}
在終端機內叫用指令時,應在選項捷徑前加上一個減號:
1php artisan mail:send 1 -Q
1php artisan mail:send 1 -Q
輸入陣列
若想要定義預期有多個輸入值的引數或選項,則可以使用 *
字元。首先,來看看這樣設定引數的例子:
1mail:send {user*}
1mail:send {user*}
呼叫這個方法的時候,user
引數在指令列中可以按照順序傳入。舉例來說,下列指令會將 user
的值設為一個內容為 foo
與 bar
的陣列:
1php artisan mail:send foo bar
1php artisan mail:send foo bar
*
字元可以與可選引數組合使用來定義,這樣一來可允許有 0 個或多個引數的實體:
1mail:send {user?*}
1mail:send {user?*}
選項陣列
定義預期有多個輸入值的選項時,每個傳入指令的選項值都應以選項名稱作為前綴:
1mail:send {user} {--id=*}23php artisan mail:send --id=1 --id=2
1mail:send {user} {--id=*}23php artisan mail:send --id=1 --id=2
輸入描述
可以通過以冒號 (:
) 區分引數名與描述來為輸入引數或選項指定描述。若需要更多空間來定義指令的話,可以將定義拆分為多行:
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send7 {user : The ID of the user}8 {--queue : Whether the job should be queued}';
1/**2 * The name and signature of the console command.3 *4 * @var string5 */6protected $signature = 'mail:send7 {user : The ID of the user}8 {--queue : Whether the job should be queued}';
指令 I/O
截取輸入
指令執行時,我們通常需要存取這些指令所接收的引數與選項值。要截取這些值,可以使用 argument
與 option
方法。若引數或選項不存在,則會回傳 null
:
1/**2 * Execute the console command.3 *4 * @return int5 */6public function handle()7{8 $userId = $this->argument('user');910 //11}
1/**2 * Execute the console command.3 *4 * @return int5 */6public function handle()7{8 $userId = $this->argument('user');910 //11}
若要將所有引數截取為陣列,則可呼叫 arguments
方法:
1$arguments = $this->arguments();
1$arguments = $this->arguments();
我們也可像截取引數一樣使用 option
方法來輕鬆地截取選項。若要將所有選項截取為陣列,請呼叫 options
方法:
1// 取得特定選項...2$queueName = $this->option('queue');34// 將所有選項作為陣列取得...5$options = $this->options();
1// 取得特定選項...2$queueName = $this->option('queue');34// 將所有選項作為陣列取得...5$options = $this->options();
為輸入進行提示
除了顯示輸出外,也可以在執行指令的過程中詢問使用者來提供輸入。ask
方法會提示使用者給定的問題,並接受使用者輸入,然後將使用者的輸入回傳至指令:
1/**2 * Execute the console command.3 *4 * @return mixed5 */6public function handle()7{8 $name = $this->ask('What is your name?');9}
1/**2 * Execute the console command.3 *4 * @return mixed5 */6public function handle()7{8 $name = $this->ask('What is your name?');9}
secret
方法與 ask
類似,但使用者在指令列輸入的過程中將看不到他們自己的輸入值。這個方法適用於像使用者詢問如密碼等機密資訊的時候:
1$password = $this->secret('What is the password?');
1$password = $this->secret('What is the password?');
要求確認
若需要使用者回答簡單的「yes / no」的確認問題,可以使用 confirm
方法。預設情況下,這個方法會回傳 false
,但若使用者在提示時輸入 y
或 yes
,則該方法會回傳 true
。
1if ($this->confirm('Do you wish to continue?')) {2 //3}
1if ($this->confirm('Do you wish to continue?')) {2 //3}
若有必要,也可以通過將 true
傳入為 confirm
方法的第二個引數來指定讓確認提示預設回傳 true
:
1if ($this->confirm('Do you wish to continue?', true)) {2 //3}
1if ($this->confirm('Do you wish to continue?', true)) {2 //3}
自動補全
anticipate
方法可以用來為可能的選項提供自動補全。不論自動補全提示了什麼,使用者一樣可以提供任意回答:
1$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);
1$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);
另外,也可以將一個閉包傳給 anticipate
方法的第二個引數。這個閉包會在每次使用者輸入字元的時候被呼叫。該閉包應接受一個字串參數,其中包含了目前使用者的輸入值,並回傳用於自動補全的選項陣列:
1$name = $this->anticipate('What is your address?', function ($input) {2 // 回傳自動補全的選項...3});
1$name = $this->anticipate('What is your address?', function ($input) {2 // 回傳自動補全的選項...3});
多重選擇問題
若需要在詢問問題時為提供使用者一組預先定義的選項,可以使用 choice
方法。也可以通過將預設選項的陣列索引傳給該方法的第三個參數,來指定沒有選擇任何選項時要回傳的預設值:
1$name = $this->choice(2 'What is your name?',3 ['Taylor', 'Dayle'],4 $defaultIndex5);
1$name = $this->choice(2 'What is your name?',3 ['Taylor', 'Dayle'],4 $defaultIndex5);
另外,choice
方法也接受第 4 個與第 5 個引數,這兩個引數分別是用來判斷選擇有效回答的最大嘗試次數,以及是否允許多重選擇:
1$name = $this->choice(2 'What is your name?',3 ['Taylor', 'Dayle'],4 $defaultIndex,5 $maxAttempts = null,6 $allowMultipleSelections = false7);
1$name = $this->choice(2 'What is your name?',3 ['Taylor', 'Dayle'],4 $defaultIndex,5 $maxAttempts = null,6 $allowMultipleSelections = false7);
撰寫輸出
若要將輸出傳送至主控台,可以使用 line
, info
, comment
, question
, warn
與 error
方法。這幾個方法會依不同目的來使用適當的 ANSI 色彩。舉例來說,我們來顯示一些一般的資訊給使用者看。通常來說,info
方法會在主控台上顯示出綠色的文字:
1/**2 * Execute the console command.3 *4 * @return mixed5 */6public function handle()7{8 // ...910 $this->info('The command was successful!');11}
1/**2 * Execute the console command.3 *4 * @return mixed5 */6public function handle()7{8 // ...910 $this->info('The command was successful!');11}
若要顯示錯誤訊息,可以使用 error
方法。錯誤訊息文字通常會以紅色顯示:
1$this->error('Something went wrong!');
1$this->error('Something went wrong!');
也可以使用 line
方法來顯示未標示色彩的純文字:
1$this->line('Display this on the screen');
1$this->line('Display this on the screen');
可以使用 newLine
方法來顯示空行:
1// 寫入一行空行...2$this->newLine();34// 寫入三行空行...5$this->newLine(3);
1// 寫入一行空行...2$this->newLine();34// 寫入三行空行...5$this->newLine(3);
表格
通過 table
方法可以很輕鬆地正確為多行列資料進行格式化。只需要提供表格的欄位名稱與表格的資料,Laravel 就會自動計算適當的表格寬高:
1use App\Models\User;23$this->table(4 ['Name', 'Email'],5 User::all(['name', 'email'])->toArray()6);
1use App\Models\User;23$this->table(4 ['Name', 'Email'],5 User::all(['name', 'email'])->toArray()6);
進度列
當有需要長時間執行的任務時,最好顯示一個能告訴使用者目前任務完成度的進度列。使用 withProgressBar
方法,Laravel 就會顯示出一個進度列,並在每次迭代過指定的迭代值時增加進度列的進度:
1use App\Models\User;23$users = $this->withProgressBar(User::all(), function ($user) {4 $this->performTask($user);5});
1use App\Models\User;23$users = $this->withProgressBar(User::all(), function ($user) {4 $this->performTask($user);5});
有時候,我們可能需要手動控制進度列何時需要增加。首先,我們先定義整個過程所需要迭代的次數。接著,在每個項目處理完後增加進度:
1$users = App\Models\User::all();23$bar = $this->output->createProgressBar(count($users));45$bar->start();67foreach ($users as $user) {8 $this->performTask($user);910 $bar->advance();11}1213$bar->finish();
1$users = App\Models\User::all();23$bar = $this->output->createProgressBar(count($users));45$bar->start();67foreach ($users as $user) {8 $this->performTask($user);910 $bar->advance();11}1213$bar->finish();
有關更進階的選項,請參考 Symfony Progress Bar 元件說明文件。
註冊指令
所有主控台指令都在 App\Console\Kernel
類別內自動註冊。該類別為專案的「主控台核心」。在該類別的 commands
方法內,可以看到一個核心 load
方法的呼叫。load
方法會掃描 app/Console/Commands
目錄並自動向 Artisan 註冊其中的各個指令。你也可以在 load
方法中加上額外的呼叫來掃描其他目錄中的 Artisan 指令:
1/**2 * Register the commands for the application.3 *4 * @return void5 */6protected function commands()7{8 $this->load(__DIR__.'/Commands');9 $this->load(__DIR__.'/../Domain/Orders/Commands');1011 // ...12}
1/**2 * Register the commands for the application.3 *4 * @return void5 */6protected function commands()7{8 $this->load(__DIR__.'/Commands');9 $this->load(__DIR__.'/../Domain/Orders/Commands');1011 // ...12}
若有需要的話,也可以通過將指令的類別名稱加至 App\Console\Kernel
類別的 $commands
屬性來手動註冊指令。若該屬性不存在,你可以手動建立。當 Artisan 啟動時,列在該屬性上的所有指令都會由 Service Container 進行解析,並向 Artisan 註冊:
1protected $commands = [2 Commands\SendEmails::class3];
1protected $commands = [2 Commands\SendEmails::class3];
通過程式碼執行指令
有時候可能需要在 CLI 以外的地方執行 Artisan 指令。舉例來說,你可能會想在路由或控制器內執行 Artisan 指令。可以使用 Artisan
Facade 的 call
方法來完成這一目標。可以傳入指令的簽章名稱或類別名稱給 call
方法的第一個引數,而指令的參數則可以陣列傳為第二個引數。指令的結束代碼(Exit Code)會被回傳:
1use Illuminate\Support\Facades\Artisan;23Route::post('/user/{user}/mail', function ($user) {4 $exitCode = Artisan::call('mail:send', [5 'user' => $user, '--queue' => 'default'6 ]);78 //9});
1use Illuminate\Support\Facades\Artisan;23Route::post('/user/{user}/mail', function ($user) {4 $exitCode = Artisan::call('mail:send', [5 'user' => $user, '--queue' => 'default'6 ]);78 //9});
或者,也可以將整個 Artisan 指令作為字串傳給 call
方法:
1Artisan::call('mail:send 1 --queue=default');
1Artisan::call('mail:send 1 --queue=default');
傳入陣列值
若指令有定義接受陣列的選項,則可將陣列傳給該選項:
1use Illuminate\Support\Facades\Artisan;23Route::post('/mail', function () {4 $exitCode = Artisan::call('mail:send', [5 '--id' => [5, 13]6 ]);7});
1use Illuminate\Support\Facades\Artisan;23Route::post('/mail', function () {4 $exitCode = Artisan::call('mail:send', [5 '--id' => [5, 13]6 ]);7});
傳入布林值
若有需要為不接受字串值的選項指定值,如 migrate:refresh
指令的 --force
旗標,則可以為該選項傳入 true
或 false
:
1$exitCode = Artisan::call('migrate:refresh', [2 '--force' => true,3]);
1$exitCode = Artisan::call('migrate:refresh', [2 '--force' => true,3]);
將 Artisan 指令放入佇列
只需要使用 Artisan
Facade 的 queue
方法,就可以將 Artisan 指令放入佇列執行,這樣這個指令就會在 佇列背景工作角色 內背景執行。在使用該方法前,請先確認是否已設定好佇列,且有執行佇列監聽程式:
1use Illuminate\Support\Facades\Artisan;23Route::post('/user/{user}/mail', function ($user) {4 Artisan::queue('mail:send', [5 'user' => $user, '--queue' => 'default'6 ]);78 //9});
1use Illuminate\Support\Facades\Artisan;23Route::post('/user/{user}/mail', function ($user) {4 Artisan::queue('mail:send', [5 'user' => $user, '--queue' => 'default'6 ]);78 //9});
可以使用 onConnection
與 onQueue
方法來指定 Artisan 指令應分派到哪個連線或佇列上:
1Artisan::queue('mail:send', [2 'user' => 1, '--queue' => 'default'3])->onConnection('redis')->onQueue('commands');
1Artisan::queue('mail:send', [2 'user' => 1, '--queue' => 'default'3])->onConnection('redis')->onQueue('commands');
在其他指令內執行指令
有時候可能需要在現有 Artisan 指令內執行另一個指令。可以通過呼叫 call
方法來完成。call
方法接受指令名稱與指令的引數與選項:
1/**2 * Execute the console command.3 *4 * @return mixed5 */6public function handle()7{8 $this->call('mail:send', [9 'user' => 1, '--queue' => 'default'10 ]);1112 //13}
1/**2 * Execute the console command.3 *4 * @return mixed5 */6public function handle()7{8 $this->call('mail:send', [9 'user' => 1, '--queue' => 'default'10 ]);1112 //13}
若有需要呼叫另一個主控台指令並忽略其所有輸出,則可使用 callSilently
方法。callSilently
方法的簽章與 call
方法相同:
1$this->callSilently('mail:send', [2 'user' => 1, '--queue' => 'default'3]);
1$this->callSilently('mail:send', [2 'user' => 1, '--queue' => 'default'3]);
處理訊號
驅動 Artisan 主控台的 Symfony Console 能夠設定指令能處理那些處理程序訊號(若有的話)。舉例來說,你可能會想要讓指令能處理 SIGINT
與 SIGTERM
訊號。
要開始處理訊號,請先在 Artisan 指令類別上實作 Symfony\Component\Console\Command\SignalableCommandInterface
介面。這個介面要求要定義兩個方法:getSubscribedSignals
與 handleSignal
:
1<?php23use Symfony\Component\Console\Command\SignalableCommandInterface;45class StartServer extends Command implements SignalableCommandInterface6{7 // ...89 /**10 * Get the list of signals handled by the command.11 *12 * @return array13 */14 public function getSubscribedSignals(): array15 {16 return [SIGINT, SIGTERM];17 }1819 /**20 * Handle an incoming signal.21 *22 * @param int $signal23 * @return void24 */25 public function handleSignal(int $signal): void26 {27 if ($signal === SIGINT) {28 $this->stopServer();2930 return;31 }32 }33}
1<?php23use Symfony\Component\Console\Command\SignalableCommandInterface;45class StartServer extends Command implements SignalableCommandInterface6{7 // ...89 /**10 * Get the list of signals handled by the command.11 *12 * @return array13 */14 public function getSubscribedSignals(): array15 {16 return [SIGINT, SIGTERM];17 }1819 /**20 * Handle an incoming signal.21 *22 * @param int $signal23 * @return void24 */25 public function handleSignal(int $signal): void26 {27 if ($signal === SIGINT) {28 $this->stopServer();2930 return;31 }32 }33}
你可能已經看得出來,getSubscribedSignals
應回傳一個包含所有指令能處理訊號的陣列,而 handleSignal
則接收訊號並根據訊號進行回應。
自訂 Stub
Artisan 主控台的 make
指令可以用來建立各種類別,如控制器、任務、資料庫遷移,以及測試。這些類別都是使用「Stub (虛設常式)」來產生的,Stub 會依據給定的輸入來填入不同的值。不過,你可能會想對這些 Artisan 產生的檔案做一些微調。要修改這些 Stub,可以通過 stub:publish
指令來將這些最常見的 Stub 安裝到專案中,如此一來就能自訂這些 Stub:
1php artisan stub:publish
1php artisan stub:publish
安裝的 Stub 會被放在專案根目錄的 stubs
目錄中。對這些 Stub 做出的任何改動都會反應到使用 Artisan 的 make
指令所產生的對應類別上。
事件
Artisan 會在執行指令的時候分派三個事件: Illuminate\Console\Events\ArtisanStarting
, Illuminate\Console\Events\CommandStarting
與 Illuminate\Console\Events\CommandFinished
。ArtisanStarting
事件會在 Artisan 開始執行後馬上被分派。接著,CommandStarting
事件會在指令開始執行前的瞬間被分派。最後,CommandFinished
事件會在指令完成執行後被分派。