本篇為 PHP 系列
什麼是 Collection
Laravel Collection 底層主要的資料結構是 PHP Array,也就是陣列。但 Laravel 透過 Collection 類別,將陣列進行封裝後,提供了比單純的陣列更加流暢 (fluent) 及更便利的用法。
另一方面,在 Collection 的設計概念中,也借用了部分函式語言程式設計 (Functional Programming) 的想法,因此學習 Collection 也替開發者帶來不同的思維模式。
Collection 完整名稱:
Illuminate\Support\Collection
先來看一個 Collection 的簡單應用:如何把 Array 中的每個值都乘以 2?
如果是傳統的陣列,可以這樣做:
$array = [1, 2, 3, 4];
for ($i = 0; $i < count($array); $i++) {
$array[$i] = $array[$i] * 2;
}
在陣列的範例中,開發者要自己處理迴圈的計數,也要自己取出值,乘以二後再寫回陣列。雖然不難,但有很多細節要留意。
而在 Collection 則可以這樣做:
$collection = collect([1, 2, 3, 4]);
$collection = $collection->map(function($value) {
return $value * 2;
});
雖然以這兩個範例來說,程式碼的量差不多,但在 Collection 的範例中,開發者不用自己處理迴圈,也不用花心力在值的取出與寫入,可以更專注在實際要做的事情。
產生 Collection
要產生 Collection 很容易,可以透過 Laravel 提供的 collect()
helper 來產生,將 Array 作為參數傳入。
$collection = collect([1, 2, 3]);
$collection = collect([
"name" => "Devin Deving",
"job" => "code farmer",
]);
不傳參數則會會產生一個空的 Collection,可以再透過下面將介紹的方法將資料寫入。
$collection = collect();
10 種 Collection 常用方法
基本存取
-
all()
all()
會回傳 collection 內實際的的 array,$collection = collect([1, 2, 3]); $array = $collection->all(); // [1, 2, 3]
-
get()
get()
可以用 key 來取出單一物件,用法類似 array 的[$key]
。但 collection 的 get 可以設定預設值,當目標 key 不存在時,會回傳預設值,若無設定預設值,則回傳null
。$collection = collect([1, 2, 3]); $number = $collection->get(0); // $number: 1
沒有明確指定 key 的 array,PHP 會自動從 0 開始編碼 (indexing) ,讓資料結構維持一至。
$collection = collect([ "name" => "Devin Deving", "job" => "code farmer", ]); $name = $collection->get("name"); // $name: "Devin Deving"
第二個參數為預設值,如果沒有設定則會回傳
null
。這樣的機制讓 key 不存在時,開發者不用自己處理特殊情境。$lang = $collection->get("lang"); // $lang: null $lang = $collection->get("lang", "PHP"); // $lang: "PHP"
-
put()
跟
get()
對應的是put()
,將物件放入指定的 key 的位置。$collection = collect([ "name" => "Devin Deving", ]); $collection->put("lang", "PHP"); $array = $collection->all(); /* [ "name" => "Devin Deving", "lang" => "PHP", ] */
put()
也可以用來複寫既有的值:$collection = collect([ "name" => "Devin Deving", ]); $collection->put("name", "Deving"); $array = $collection->all(); /* [ "name" => "Deving", ] */
基本判斷
-
has() / contains()
has()
可以用來判斷 collection 是否包含某個 key。contains()
可以用來判斷 collection 是否包含某個 值。$collection = collect([ "name" => "Devin Deving", "job" => "code farmer", ]); $collection->has('name'); // true $collection->has('lang'); // false $collection->contains('Devin Deving'); // true $collection->contains('PHP'); //false
-
count() / isEmpty() / isNotEmpty()
這邊介紹一些跟計算個數有關的方法。
count()
可以用來計算 collection 中有多少個元件。isEmpty()
可以用來判斷 collection 是否為空,不需要自己寫數量等於零的判斷;相對的isNotEmpty()
,則是可以用來判斷 collection 不為空。$collection = collect(["Apple", "Banana"]); $emptyCollection = collect(); $collection->count(); // 2 $emptyCollection->count(); // 0 $collection->isEmpty(); // false $emptyCollection->isEmpty(); // true $collection->isNotEmpty(); // true $emptyCollection->isNotEmpty(); // false
操作
-
sort() / sortKeys()
Collection 提供了一系列排序的方法,
sort()
可以針對值來排序,而sortKeys()
則是針對 key 來排序。sort()
範例:$collection = collect([7, 2, 1, 4, 10]); $sorted = $collection->sort(); $array = $sorted->all(); // $array: [1, 2, 4, 7, 10]
sortKeys()
範例:$collection = collect([ 'A' => 'AAAA', 'C' => 'CCCC', 'B' => 'BBBB', 'D' => 'DDDD', ]); $sorted = $collection->sortKeys(); $array = $sorted->all(); /* $array: [ "A" => "AAAA" "B" => "BBBB" "C" => "CCCC" "D" => "DDDD" ] */
-
splice()
splice()
可以用來切分 Collection,它需要兩個參數,第一個是開始位置,第二個是數量,若沒有第二個參數則是取到最後。$array = [0, 1, 2, 3, 4, 5]; // 從位置 1 開始後所有值 collect($array)->splice(1); // [1, 2, 3, 4, 5] // 從位置 1 開始,取 2 個 collect($array)->splice(1, 2); // [1, 2] // 從位置 1 開始,取 4 個 collect($array)->splice(1, 4); // [1, 2, 3, 4]
splice()
會改變 Collection 本身,因此範例中每次都重新建立 Collection,這樣的行為跟 Collection 的特性有關。 -
map()
map()
會遍歷 Collection 中所有的值,透過 callback 函式來操作 Collection 中的值,並回傳一個新的 Collection。callback 函式允許兩個參數,第一個是每個一個元件的值,第二個是每個元件的 key。
如同文章一開始的的範例,傳入 map 的是一個 callback,map 會依序把 Collection 中的值傳入 callback 中,取得運算結果後傳回一個新的 Collection,其中包含更新後的值。
$collection = collect([1, 2, 3, 4]); $newCollection = $collection->map(function($value) { return $value * 2; }); $newCollection->all(); // [2, 4, 6, 8]; $collection->all(); // [1, 2, 3, 4];
map()
不會影響原本的 Collection,而是回傳一個新的 Collection。亦可以使用 key 來做操作:
$collection = collect([ "name" => "Devin Deving", "job" => "code farmer", ]); $collection = $collection->map(function($value, $key) { return $key . " : " . $value; }); $array = $collection->all(); /* $array: [ "name" => "name : Devin Deving" "job" => "job : code farmer" ] */
-
each ()
each()
跟map()
類似,但是each()
並不會回傳新的 Collection,亦不會改變原本的 Collection。就是單純的遍歷 Collection 中的所有的元件。因此
each()
比較適合用於呼叫其他函式,而不是用來改變 Collection 的值。$collection = collect([ "name" => "Devin Deving", "job" => "code farmer", ]); $collection->each(function($value, $key) { showUserInfo($key, $value); });
-
reject() / filter()
reject()
可以用來拒絕掉不想要的資料,一樣是透過 callback 來進行。當 callback 回傳true
時,則該筆資料會被拒絕掉。而
filter()
則是跟reject()
相對的,只保留想要的資料,因此 callback 回傳true
時,該筆資料會保留。利用
reject()
拒絕掉<= 2
的值:$collection = collect([0, 1, 2, 3, 4]); $newCollection = $collection->reject(function ($value, $key) { return $value <= 2; }); $newCollection->all(); // [3, 4]
利用
filter()
保留<= 2
的值:$collection = collect([0, 1, 2, 3, 4]); $newCollection = $collection->filter(function ($value, $key) { return $value <= 2; }); $newCollection->all(); // [0, 1, 2]
reject()
和filter()
都跟map()
一樣,不會影響原本的 Collection,而是回傳一個新的 Collection。
本篇為 PHP 系列