php – 在方法使用展開運算子的類型提示替換陣列提示

這裡介紹兩種用法的比較:

我們開發常常會有一種情況,把一筆陣列資料輸入到某隻 method(),但因為是陣列,在強型別 type hinting 的時候,不知道怎麼做限制。例如加入購物車 Cart,可能會放入多筆商品,常見的寫法是:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php $products = [ // 這裡省略產品類別範例 // Product("商品名稱", "數量", "單價", "單位") new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ]; $cart = new Cart($products); |
我們常見設計的購物車類別:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php class Cart { /** * 購物車的商品項目 * @var array */ private array $items; /** * 建構子把輸入的參數賦予到類別屬性 * @param array $products */ public function __construct(array $products) { $this->items = $products; } } |
這會有一個小問題,我們在建構子 __construct(array $products) 使用強型別規範輸入 array 卻無法明定陣列中的每項型態,這對接手或日後維護的人來說,無法一目瞭然陣列裡面的項目長什麼樣子。
如果我們可以針對陣列中的每個值做類型提示,那麼無論閱讀上或是搭配 IDE 如 phpStorm 都能做出優美的提示。 因此能透過 “…” 參數語法來表示,以下修改上述範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 方法一,一次丟入陣列 $products = [ new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ]; // 注意帶入的時候要加上 "..." $cart = new Cart(...$products); // 方法二,在參數追加 $cart = new Cart( new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ); |
那麼購物車類別如何修改?其實很簡單
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php class Cart { private array $items; /** * 我們透過 ... 語法,代表參數可以輸入多筆類別是 Product 的物件 * @param Product[] $products */ public function __construct(Product ...$products) { $this->items = $products; } } |
上面建構子改良後有兩種用法,方法一是我覺得實務上最常用的方式
1 2 3 4 5 6 7 |
$products = [ new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ]; $cart = new Cart(...$products); |
因為使用者放入的商品數量並不固定,因此方法一實務上最常見。IDE 也能非常清楚的提示:

而方法二適合用在我們寫 Code 的應用上
1 2 3 4 5 6 |
$cart = new Cart( new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ); |
例如 Laravel 的 dd() 就是個好懂的範例
1 2 3 4 |
dd($name); dd($name, $age); |
實務上使用 Interface
中型實務上,展開運算子的強型別我們會使用 Interface 而不是 class 。例如這項發票中心系統 InvoiceCenter 的建構子簡化如下:

注意函式參數第三個,我們在 type hint 做展開運算子使用的是介面 ProductInterface 而不是 類別 Product。因此我們實例化類別的時候會是這樣:

沒錯就是依賴反轉,我們把這項發票中心系統 InvoiceCenter,所依賴的第三方廠商 API 從外部注入,也就是說廠商A
- EzPay 實作 InvoicePlatformInterface
- User 實作 UserInterface
- Product 實作 ProductInterface
我們要換成廠商B,也許叫做 xxPay,那麼他們的發票系統我們也只需要實作這三項 Interface。而第三個參數 new Product() 就是我們本篇提到的應用。IDE 會告訴你這個陣列的每個類別,務必實作 ProductInterface

假設我們帶入任何一項類別,沒有實作介面 ProductInterface 那麼會輕鬆報錯給你看,這對維護人員太有效了

本篇概念參考來源 https://stackoverflow.com/questions/34273367/type-hinting-in-php-7-array-of-objects