變數
變數就像小孩一樣,生的越多負擔越大
程式碼多半會髒,大概有八成是因為變數太多了。變數多會延伸出幾個問題:
命名會變困難,因為簡單的單字可能都被使用
變數會長大,也會有叛逆期。同一個變數經歷過幾個不同階段的迴圈以及 by reference 的修改,這支變數充滿了未知數。
如果不只一個變數再重複利用,還有多個變數時,就會直接照成可怕的耦合。這大概就像延長線上的所有電線打結的樣子,你必須要順著頭或尾一步一步的解開這條線的來龍去脈。
先舉一個待解決的例子(這個案例算是非常輕微):
<?php
// bad code
function example () {
$result = [];
$products = [];
$disabledProductIds = [];
// 透過 by reference 更新變數資料
$this->getProducts($products);
foreach($products as $key => $product) {
// 移除狀態為 false 的商品
if ($product->status === false) {
unset($products[$key]);
$disabledProductIds[] = $product->id;
continue;
}
// 商品名字加上原本索引
$product->name .= "($key)";
}
$products = array_value($products);
$result['products'] = $products;
$result['disabled_ids'] = $disabledProductIds;
return $result;
}
總共養了三支變數,當中 $products
還有 by Reference 的方式更新,接著又使用 unset
移除資料。
這個範例會對於之後的維護和擴充產生幾個問題:
當要對
$products
操作的時候,要從頭dd($products)
這個變數來確定應該怎麼寫改。如果要知道這個功能最後輸出什麼結果,就必須要
dd($result)
,這還只能勉強猜到變數的內容,因為難保之後會不會有人從中間選擇性寫入其他值。
減少變數的方法有兩種:
將變數丟到新的類別或方法去處理,但會分散邏輯
使用 fluent interface 去解,Laravel Collection 就能很漂亮的解套了
<?php
// good code
// 總共只使用一個變數
function example () {
// `get products` 應直接回傳 products,而些 reference
$products = $this->getProducts();
// 雖然會多跑一次迴圈,但對於可讀性來說,是非常划算
return [
'products' => collect($products)
// 已啟用商品
->filter(fn($product) => $product->status)
->map(fn($prodcut, $key) => [
'id' => $product->id,
'name' => "{$product->name}({$key})",
'status' => $product->status,
])
->values()
->toArray(),
'disabled_ids' => collect($products)
// 已停用商品
->filter(fn($product) => $product->status === false)
->pluck('id')
->toArray(),
];
}
減少未知的變數
如果最後輸出的變數是陣列或 Collection,建議重新 Map 一次,可以有效減少未知的部分,還能集中程式碼邏輯。
return $products;
// 單層 array
return [
// 商品
'id' => $product->id,
'name' => $product->name,
'created_at' => $product->created_at->toDateTimeString(),
'updated_at' => $product->updated_at->toDateTimeString(),
// 商品規格
'specs' => $product->specs->map(fn($spec) => [
'id' => $spec->id,
'name' => $spec->name,
'stocks' => $spec->stocks,
])
];
// 多層 Array 或多層 Collection
return collect($products)->map(fn($product) => [
// 商品
'id' => $product->id,
'name' => $product->name,
'created_at' => $product->created_at->toDateTimeString(),
'updated_at' => $product->updated_at->toDateTimeString(),
// 商品規格
'specs' => $product->specs->map(fn($spec) => [
'id' => $spec->id,
'name' => $spec->name,
'stocks' => $spec->stocks,
])
]);
Last updated
Was this helpful?