Larvel透過GeneratorCommand使用artisan產出php執行檔
基本概念
將原始碼寫在.stub檔中,內容中如果有需要替換的則使用{{ }} 標記,例如 namespace {{ namespace }};
GeneratoreCommand會讀出.stub檔案將需要替換的文字替換完成後依照namespace寫入.php檔案
幾個需要理解的method與參數
首先參數的部分,固定第一個為name,也就是要產出的檔案名稱
| 
					 1  | 
						php artisan GeneratorCommand {name}  | 
					
method: getStub()
| 
					 1  | 
						protected function getStub(): string  | 
					
需要return .stub檔案的路徑,如果.stub檔案在vendor資料夾中則可以透過上篇說明來取得package中的檔案
範例可以像這樣子,class中依照上一篇說明定義好get_file_path後,就可以找到指定的Vendor\package\路徑下的檔案了
如果是在同一個專案目錄中,則直接return專案中路徑即可
| 
					 1 2 3 4  | 
						protected function getStub(): string {     return $this->get_file_path("/http/Controllers"); }  | 
					
method: getDefaultNamespace()
| 
					 1  | 
						protected function getDefaultNamespace($rootNamespace): string  | 
					
需要return 產出php檔正確擺放位置的namespace,例如
| 
					 1 2 3 4  | 
						protected function getDefaultNamespace($rootNamespace): string {     return $rootNamespace . "\Http\\Controllers"; }  | 
					
這樣子就會把產出的php檔案放在app\Http\Controllers中
method: getNameInput()
| 
					 1  | 
						protected function getNameInput(): string  | 
					
return值作為檔案的名稱,也就是return command第一個參數name就行了,通常會把class name做大駝峰處理,範例如下
| 
					 1 2 3 4  | 
						protected function getNameInput(): string {     return Str::studly(trim($this->argument('name'))); }  | 
					
method: buildClass()
| 
					 1  | 
						protected function buildClass($name): array|string  | 
					
如果產出的php檔沒有其他需要替換的標記,或者沒有其他邏輯需要處理是可以不必處理buildClass()這個method,這邊提供一個範例
把stub內容中多組tag紀錄在$this->replace_tags中,然後再buildClass method中替換掉他
| 
					 1 2 3 4 5 6 7 8 9 10 11 12  | 
						protected function buildClass($name): array|string {     $stub = $this->files->get($this->getStub());     $namespace = $this->replaceNamespace($stub, $name)->replaceClass($stub, $name);     $replacedStub = $namespace;     foreach ($this->replace_tags as $tag => $text){         $replacedStub = str_replace("{{ {$tag} }}", $text, $replacedStub);     }     return $replacedStub; }  | 
					
method: handle()
| 
					 1  | 
						public function handle(): ?bool  | 
					
如果在產出檔案前,有需要對class的其他參數做調整,可以複寫handle() method,記得最後要return parent::handle()就好
例如像這樣
| 
					 1 2 3 4 5 6  | 
						public function handle(): ?bool {     #你想要的內容寫在這裡     return parent::handle(); // TODO: Change the autogenerated stub }  | 
					
method: interact()
| 
					 1  | 
						protected function interact(InputInterface $input, OutputInterface $output)  | 
					
假設需要對輸入的參數做一些調整,可以透過複寫interact來達成,下面的範例處理了name參數,讓他變成首字大寫
| 
					 1 2 3 4 5 6 7 8 9 10 11 12  | 
						/**  * Override  * 重新處理name參數  */ protected function interact(InputInterface $input, OutputInterface $output) {     parent::interact($input, $output);     if ($input->hasArgument('name')) {         $name = implode('/',array_map('ucfirst',explode('/',$input->getArgument('name'))));         $input->setArgument('name',$name);     } }  | 
					
最後提供一個完整範例
將virtualorz\mysdk中的 Stuns/http/controllers.stub 生成 /app/Http/Controllers/CustomerController.php
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73  | 
						#command.php <?php namespace App\Console\Commands; use Illuminate\Console\GeneratorCommand; use Illuminate\Support\Str; class MakeCustomerController extends GeneratorCommand {     protected $name = 'make:my-controller';     protected $description = 'Create my controller class';     protected string $stub_path = 'http/ClassController';     protected string $target_path = '\Http\\Controllers';     protected array $replace_tags = ['use_string'=>'use App\Services\Config\ConfigService'];     protected function getStub(): string     {         return $this->get_file_path($this->stub_path);     }     protected function getDefaultNamespace($rootNamespace): string     {         return $rootNamespace . $this->target_path;     }     protected function getNameInput(): string     {         return Str::studly(trim($this->argument('name')));     }     protected function buildClass($name): array|string     {         $stub = $this->files->get($this->getStub());         $namespace = $this->replaceNamespace($stub, $name)->replaceClass($stub, $name);         $replacedStub = $namespace;         foreach ($this->replace_tags as $tag => $text){             $replacedStub = str_replace("{{ {$tag} }}", $text, $replacedStub);         }         return $replacedStub;     }     protected function get_file_path($path): string     {         $loader = $this->_getClassLoader();         $psr4 = $loader->getPrefixesPsr4();         $namespace = 'virtualorz\\mysdk\\';         $stubFilename = "Stubs/{$path}.stub"; // Stub 檔案名稱         $stub_path_location = '';         foreach ($psr4 as $prefix => $paths) {             if (str_starts_with($namespace, $prefix)) {                 foreach ($paths as $path) { // 處理多個路徑                     $relativePath = str_replace($prefix, '', $namespace);                     $relativePath = str_replace('\\', '/', $relativePath);                     $stubPath = $path . '/' . $relativePath . $stubFilename;                     if (file_exists($stubPath)) {                         $stub_path_location =  $stubPath;                     }                 }             }         }         return $stub_path_location;     }     protected function _getClassLoader()     {         return require base_path('vendor/autoload.php');     } }  | 
					
| 
					 1 2 3 4 5 6 7 8 9 10 11 12  | 
						Controllers.stub <?php namespace {{ namespace }}; {{ use_string }} class {{ class }} extends Controller { }值  | 
					
執行命令
| 
					 1  | 
						php artisan make:my-controller CustomerController  |