告別義大利麵:Laravel 10 專案架構進化論
專業工程師必讀!我們解析 Laravel 10 如何透過強型別、Service Action Pattern 和 Form Request 終結技術債。別讓自由度成為陷阱,立即行動,將你的程式碼從陳年義大利麵進化為穩固、可擴展的企業級應用!
你的 Laravel 專案是技術債炸彈還是傳世藝術品?Laravel 10 專案架構最佳實務指南
嗨,我是 Eric,浪花科技的資深工程師。如果你跟我一樣在程式碼的海洋裡游了十幾年,你一定聞過那種味道——那種打開一個接手專案時,撲面而來的「陳年義大利麵」味。Controller 裡面塞了 500 行的商業邏輯,Model 模型互相依賴到像個打結的耳機線,View 裡面甚至直接寫了 SQL 查詢(這真的會讓我心臟漏一拍)。
Laravel 是一個非常自由的框架,這也是它的雙面刃。Laravel 10 引入了許多強大的 PHP 8.1+ 特性,如果你還在用 Laravel 5 的思維寫 Laravel 10,那你正在錯過讓專案從「玩具」進化成「企業級應用」的機會。今天,我們不談太高深的微服務拆分,我們來談談在單體式架構(Monolithic)下,如何透過Laravel 10 專案架構最佳實務,把你的程式碼寫得像首詩,而不是一場災難。
1. 擁抱強型別 (Type Hints) 與回傳類型
Laravel 10 的應用程式骨架(Skeleton)已經全面擁抱 PHP 的型別系統。這不是為了裝酷,而是為了讓你的程式碼「剛性」更強,減少那些因為 null 或是錯誤資料型態導致的隱形 Bug。
在 Laravel 10 中,請強迫自己和團隊加上參數型別與回傳型別宣告 (Return Types)。這能讓 IDE 更好地輔助你,也能讓程式碼本身即文件。
不推薦的寫法 (Loose Typing):
public function store($request)
{
// 這裡的 $request 是什麼? array? Request 物件?
// 回傳的是什麼? JSON? View?
// 這種寫法要看完整個 function 才知道在幹嘛
}
Laravel 10 推薦寫法 (Strict Typing):
use Illuminate\Http\RedirectResponse;
use App\Http\Requests\StoreUserRequest;
public function store(StoreUserRequest $request): RedirectResponse
{
// 清楚知道輸入是有驗證過的 Request,輸出必定是轉址
$this->userService->create($request->validated());
return to_route('users.index');
}
2. 拒絕肥大的 Controller:善用 Service Layer 與 Action Pattern
這是我最常嘮叨的一點:「Controller 只是交通警察,不是法官。」
Controller 的職責應該僅限於:接收請求、驗證資料(交給 Form Request)、呼叫邏輯層、回傳回應。絕對不要在 Controller 裡面寫複雜的 `if-else` 商業邏輯或是直接操作 Eloquent 的複雜查詢。
在 Laravel 10 中,我們可以更靈活地使用 Service Pattern 或是近年很流行的 Action Pattern (單一職責類別)。
- Service Pattern: 適合處理一整組相關的邏輯(例如
UserService包含註冊、更新、刪除)。 - Action Pattern: 適合單一且複雜的業務邏輯(例如
PublishArticleAction)。
這樣做的好處是,當你以後需要透過 CLI (Artisan Command) 或 API 觸發同樣的邏輯時,你不需要複製貼上程式碼,只要注入這個 Service 或 Action 即可。
3. Form Request 是你的第一道防線
拜託,別再 Controller 裡面寫 $request->validate([...]) 了。這會讓你的 Controller 變得很髒。
使用 Laravel 的 Form Request 功能,將驗證邏輯獨立出來。這不僅讓 Controller 乾淨,還能複用驗證規則。在 Laravel 10 中,你甚至可以在 Form Request 中定義 prepareForValidation 來預處理資料。
// app/Http/Requests/StoreProductRequest.php
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'price' => ['required', 'integer', 'min:0'],
'status' => ['required', Rule::in(ProductStatus::cases())], // 善用 PHP 8.1 Enums
];
}
4. 善用 Enums (列舉) 取代魔法數字
如果你的程式碼充滿了 if ($status == 1) 或 if ($type == 'admin'),請立刻停下來。這種「魔法數字」或「魔法字串」是維護的惡夢。
PHP 8.1 引入的 Enum 是 Laravel 10 開發者的好朋友。你可以結合 Laravel 的 Model Casting,讓資料庫存的是整數或字串,但在程式碼中操作的是強型別的 Enum 物件。
// app/Enums/OrderStatus.php
enum OrderStatus: string
{
case PENDING = 'pending';
case PAID = 'paid';
case SHIPPED = 'shipped';
}
// 在 Model 中使用
protected $casts = [
'status' => OrderStatus::class,
];
// 在程式邏輯中
if ($order->status === OrderStatus::PAID) {
// 做些什麼
}
5. 模型 (Model) 應該要「瘦」還是「胖」?
這是一個哲學問題。但我建議 Model 應該包含與資料庫交互的邏輯(如 Scopes, Accessors, Mutators, Relations),但不應該包含「商業流程邏輯」。
善用 Local Scopes 來封裝常用的查詢條件,讓你的查詢語句像英文句子一樣易讀。
糟糕的查詢寫法:
$users = User::where('active', 1)
->where('created_at', '>', now()->subDays(7))
->orderBy('created_at', 'desc')
->get();
優雅的 Scope 寫法:
// User Model 內定義 Scope
public function scopeActive(Builder $query): void { ... }
public function scopeRecent(Builder $query): void { ... }
// 使用時
$users = User::active()->recent()->get();
6. 依賴注入 (Dependency Injection) vs. Facades
Laravel 的 Facades (如 File::put(), Route::get()) 非常方便,但也常被批評難以測試。雖然 Laravel 10 的 Facades 其實很容易 Mock,但在編寫核心商業邏輯(Service/Action)時,我更推薦使用 Constructor Injection (建構子注入)。
這能清楚地列出該類別的依賴關係,並利用 PHP 8 的 Constructor Property Promotion 讓程式碼更簡潔。
class ProcessOrderAction
{
public function __construct(
protected PaymentGateway $payment,
protected InventoryService $inventory
) {}
public function execute(Order $order)
{
// ...
}
}
結論:架構是為了未來的自己
寫程式最爽的時刻不是寫完的那一刻,而是三個月後你回來看這段程式碼,發現你依然看得懂,而且能在一分鐘內加上新功能。Laravel 10 提供了非常棒的工具讓我們實踐 Clean Code,重點在於你是否願意在初期多花一點時間去設計架構。
別讓你的專案變成技術債炸彈,從今天開始重構吧!
常見問題 (FAQ)
Q1: Repository Pattern 在 Laravel 10 中還是必要的嗎?
這取決於專案規模。對於中小型專案,直接使用 Eloquent Model 通常就足夠高效且直觀。Repository Pattern 往往會增加不必要的抽象層。除非你有明確需求(例如未來可能更換資料庫,或需要極度嚴格的單元測試隔離),否則 Service Layer 搭配 Eloquent 通常是更現代且實用的選擇。
Q2: Action Pattern 和 Service Pattern 我該選哪一個?
沒有標準答案。如果你的業務邏輯非常單一且明確(例如:「發送歡迎信」),Action Pattern (Single Class) 非常適合。如果是一組相關的操作(例如:「使用者管理」包含 CRUD),Service Pattern 將這些方法群組起來會比較好管理。許多大型專案會混合使用兩者。
Q3: 既有的大型舊專案如何導入這些最佳實務?
不要試圖一次重寫!採用「童子軍原則」:每次修改檔案時,讓它比你發現時更乾淨一點。從新功能開始採用新架構,對於舊程式碼則在需要維護時逐步重構。例如,先將一段寫在 Controller 的邏輯抽取成 Action,慢慢改善整體體質。
延伸閱讀
- 拒絕義大利麵!Laravel 多租戶 (Multi-tenant) 系統設計實戰:從資料庫隔離到動態切換的 SaaS 煉金術
- Code 不是能動就好!Laravel Blade 模板終極聖經:寫出讓同事跪著拜讀的優雅程式碼
- 你的 Laravel Webhook 在裸奔嗎?資深工程師的終極安全聖經:從簽名驗證到防重放攻擊
不想讓你的 Laravel 專案變成難以維護的怪獸?
無論是架構規劃、效能優化,還是技術債重構,浪花科技的資深團隊都能為您提供最專業的技術支援。讓我們幫您打造穩固、可擴展的數位基石。






