Laravel 集合是 Laravel 框架中一個十分有用的工具。
Laravel 集合就像是在 PHP 中的陣列,但會更好用。
在這篇教程中,我們將會體驗一些集合使用時的實用技巧。
集合(Collection)
Illuminate\Support\Collection
類了提供一個便捷的運算元組的封裝。
集合 Collection
類實現了部分 PHP 和 Laravel 的介面,例如:
- ArrayAccess - 用於運算元組物件的介面。
- IteratorAggregate - 用於建立外部迭代器的介面。
- JsonSerializable
你可以在這裡檢視其餘已實現的介面。
建立一個新的集合
一個集合可以使用 collect()
幫助函式基於一個陣列被建立 或者直接通過 Illuminate\Support\Collection
類例項化。
一個非常簡單的使用 collect()
幫助函式的示例:
$newCollection = collect([1, 2, 3, 4, 5]);
複製程式碼
一個更復雜的示例:
<?php
namespace app\Http\Controllers;
use Illuminate\Support\Collection;
class TestController extends Controller
{
/**
* Create a new collection using the collect helper method.
*/
public function helperCollection()
{
$newCollection = collect([1, 2, 3, 4, 5]);
dd($newCollection);
}
/**
* Create a new collection with a Collection class instance.
*/
public function classCollection()
{
$newCollection = new Collection([1, 2, 3, 4, 5]);
dd($newCollection);
}
}
複製程式碼
這個幫助函式用起來要簡單很多因為你再不需要例項化 Illuminate\Support\Collection
類。
我也有用到 dd()
幫助函式來在瀏覽器中顯示集合。看起來大概會是這樣子。
Eloquent ORM 集合
Laravel Eloquent ORM 也以集合的形式返回資料。
Eloquent ORM 的呼叫會以集合的形式返回資料
為了演示這個效果,我將初始化一個 Sqlite 資料庫。
我們將用 Laravel 框架預置的遷移檔案來建立一個使用者表,然後填充10條資料到使用者表中。
/**
* 從使用者表獲取使用者列表
*/
public function getUsers()
{
$users = User::all();
dd($users);
}
複製程式碼
該控制器方法會返回一個如下顯示的所有使用者的 Laravel 集合。
你可以通過箭頭符號便捷的訪問集合屬性。至於例項,想要獲取 $users
集合的第一個使用者的名字,我們可以這樣做。
/**
* 獲取第一個使用者的名字
*/
public function firstUser()
{
$user = User::first();
dd($user->name);
}
複製程式碼
建立我們的示例集合
我們將會使用一些最有用的集合操作技巧,你一定會覺得很好用。
在接下來的幾個章節中,我將會用到下面這套使用者表的資料以及一些自定義的集合來達到演示的目的。雖然我們這裡是手動建立,但使用 Laravel 的模型工廠來建立也是可以的。
Array
(
[0] => Array
(
[id] => 1
[name] => Chasity Tillman
[email] => qleuschke@example.org
[age] => 51
[created_at] => 2016-06-07 15:50:50
[updated_at] => 2016-06-07 15:50:50
)
...
)
複製程式碼
查詢資料
有多種方法可以在集合中查詢資料。
contains
contains()
方法可以傳一個單一值,或一組鍵 / 值對或者一個回撥函式,然後它會返回一個布林值來告知目標內容是否在集合中。
/**
* 判斷鍵 / 值對或回撥內容是否存在於集合中
*
*
* @return true or false
*/
public function contains()
{
$users = User::all();
$users->contains('name', 'Chasity Tillman');
//true
$collection = collect(['name' => 'John', 'age' => 23]);
$collection->contains('Jane');
//false
$collection = collect([1, 2, 3, 4, 5]);
$collection->contains(function ($key, $value) {
return $value <= 5;
//true
});
}
複製程式碼
where
通過鍵值對的形式, 用 where 方法檢索集合.
where() 方法還可以被鏈式呼叫。
/**
* 使用 where 方法找到匹配的資料
*
* 通過鏈式呼叫來增加匹配條件
*/
public function where()
{
$users = User::all();
$user = $users->where('id', 2);
// 找出 id 為 2 的使用者
$user = $users->where('id', 1)
->where('age', '51')
->where('name', 'Chasity Tillman');
// 找出 user 集合中 id 為 1,年齡為 51 歲,名叫 Chasity Tillman 的使用者
}
複製程式碼
還有一些像 where-like
這種用於檢索的方法,我就不一一列舉的,大家可以通過 Laravel 的官方文件檢視。
可以著重看下面幾個:
-
whereIn() - 以鍵值對為引數檢索集合,其中值必須是組數。
-
search() - 在一個集合中檢索值,如果有值,返回其索引,如果沒有,則返回
false
。 -
has() - 檢視鍵值對是否存,返回布林值。
過濾資料
你可能已經猜到了,用 filter()
方法過濾。
你可能也已經想到了, filter 方法會接收一個回撥函式作為引數,在回撥函式中做判斷的邏輯,對嗎?你是這麼想的嗎?
/**
* 使用 filter 方法,找出所有年齡小於 35 的使用者
*/
public function filter()
{
$users = User::all();
$youngsters = $users->filter(function ($value, $key) {
return $value->age < 35;
});
$youngsters->all();
// 所有年齡小於 35 的使用者
}
複製程式碼
filter 方法會接收一個回撥函式作為引數,回撥函式的引數是鍵值對,具體篩選的邏輯寫在函式裡面,並且會返回所有符合條件的值。
這裡還用到了 all()
方法,它會返回一個集合裡的所有值。
排序 / 排序資料
集合允許我們能夠使用兩種簡單的方法對資料進行排序 :-
sortBy()
- 給定資料進行升序排序sortyByDesc()
- 給定資料降序排序
排序方法接受一個鍵或回撥函式引數用於對集合進行排序。
/**
* 排序方法接受一個鍵或回撥函式引數
* 用於對集合進行排序。
*/
public function sortData()
{
$users = User::all();
$youngestToOldest = $users->sortBy('age');
$youngestToOldest->all();
//列出以年齡升序的所有使用者
$movies = collect([
[
'name' => 'Back To The Future',
'releases' => [1985, 1989, 1990]
],
[
'name' => 'Fast and Furious',
'releases' => [2001, 2003, 2006, 2009, 2011, 2013, 2015, 2017]
],
[
'name' => 'Speed',
'releases' => [1994]
]
]);
$mostReleases = $movies->sortByDesc(function ($movie, $key) {
return count($movie['releases']);
});
$mostReleases->toArray();
//列出以上映總數降序排序的電影
dd($mostReleases->values()->toArray());
/*
列出以上映總數降序排序的電影並重置鍵值
*/
}
複製程式碼
排序方法維護每個值的鍵。 雖然這對您的應用程式可能很重要,但您可以通過鏈式 values()
方法將它們重置為預設的基於零的增量值。
像往常一樣,我還使用一個將集合轉換為陣列的集合方法 toArray()
。
資料 分組
###groupBy
對集合進行分組有助於理解您的資料。 groupBy 方法接受鍵或回撥函式,並根據鍵值或返回的回撥值返回分組集合。
/**
* groupBy 返回基於鍵或回撥函式分組的資料
* 邏輯
*/
public function grouping()
{
$movies = collect([
['name' => 'Back To the Future', 'genre' => 'scifi', 'rating' => 8],
['name' => 'The Matrix', 'genre' => 'fantasy', 'rating' => 9],
['name' => 'The Croods', 'genre' => 'animation', 'rating' => 8],
['name' => 'Zootopia', 'genre' => 'animation', 'rating' => 4],
['name' => 'The Jungle Book', 'genre' => 'fantasy', 'rating' => 5],
]);
$genre = $movies->groupBy('genre');
/*
[
"scifi" => [
["name" => "Back To the Future", "genre" => "scifi", "rating" => 8,],
],
"fantasy" => [
["name" => "The Matrix", "genre" => "fantasy", "rating" => 9,],
["name" => "The Jungle Book", "genre" => "fantasy", "rating" => 5, ],
],
"animation" => [
["name" => "The Croods", "genre" => "animation", "rating" => 8,],
["name" => "Zootopia", "genre" => "animation", "rating" => 4, ],
],
]
*/
$rating = $movies->groupBy(function ($movie, $key) {
return $movie['rating'];
});
/*
[
8 => [
["name" => "Back To the Future", "genre" => "scifi", "rating" => 8,],
["name" => "The Croods", "genre" => "animation", "rating" => 8,],
],
9 => [
["name" => "The Matrix", "genre" => "fantasy", "rating" => 9,],
],
4 => [
["name" => "Zootopia","genre" => "animation", "rating" => 4,],
],
5 => [
["name" => "The Jungle Book","genre" => "fantasy","rating" => 5,],
],
]
*/
}
複製程式碼
獲取資料子集
給定一組資料,然後是一個集合,您可能希望得到它的一部分。 這可能是:
- 前2條記錄
- 最後2條記錄
- 除2組以外的所有記錄。
集合操作幫助我們使用少量的方法完成這些操作。
take
take 方法接受一個整數值並返回指定的項數。給定一個負數,take()
返回集合末尾的指定項數。
/**
* take 方法返回集合中的 n 個項數。
* 給定 -n ,返回最後 n 個項數
*/
public function takeMe()
{
$list = collect([
'Albert', 'Ben', 'Charles', 'Dan', 'Eric', 'Xavier', 'Yuri', 'Zane'
]);
//獲取前兩個名字
$firstTwo = $list->take(2);
//['Albert', 'Ben']
//獲取最後兩個名字
$lastTwo = $list->take(-2);
//['Yuri', 'Zane']
}
複製程式碼
chunk
chunk 方法將集合分割成大小為 n 的較小集合。
/**
* Chunk(n) 返回大小為 n 的較小集合,每個都來自原始集合
*
*/
public function chunkMe()
{
$list = collect([
'Albert', 'Ben', 'Charles', 'Dan', 'Eric', 'Xavier', 'Yuri', 'Zane'
]);
$chunks = $list->chunk(3);
$chunks->toArray();
/*
[
["Albert", "Ben", "Charles",],
[3 => "Dan", 4 => "Eric", 5 => "Xavier",],
[6 => "Yuri", 7 => "Zane",],
]
*/
}
複製程式碼
這裡有很多方法可以達到效果。
當你傳遞資料到 blade 頁面時,你可以將他分塊以一次獲得 n 行資料,例如,將每 3 個名字裝進一行。
@foreach($list->chunk(3) as $names)
<div class="row">
@foreach($names as $name)
{{ $name }}
@endforeach
</div>
@endforeach
複製程式碼
你也可以使用 collapse()
方法將更新的集合組轉成一個大的集合,來反轉 chunk
方法,請檢視此 here.
遍歷資料
map
map 方法會遍歷集合,將每個元素傳入一個閉包函式,該閉包函式的返回值將替換原來的元素值。
我們建立一個由名字組成的集合,並使用 map 方法返回一個由對應名字長度組成的集合。
/**
* map function iterates a collection through a callback
* function and performs an operation on each value.
*/
public function mapMe()
{
$names = collect([
'Albert', 'Ben', 'Charles', 'Dan', 'Eric', 'Xavier', 'Yuri', 'Zane'
]);
$lengths = $names->map(function ($name, $key) {
return strlen($name);
});
$lengths->toArray();
//[6, 3, 7, 3, 4, 6, 4, 4,]
}
複製程式碼
transform
雖然 map 方法建立了一個新的集合,但有時候你可能想去修改原始的集合內容。transform 提供了一個回撥方法,並對同一個集合進行操作。
因為轉換不會產生新的集合,所以你無需把它賦給新的值。
/**
* Transform 操作原始的集合。
*/
public function transformMe()
{
$names = collect([
'Albert', 'Ben', 'Charles', 'Dan', 'Eric', 'Xavier', 'Yuri', 'Zane'
]);
$names->transform(function ($name, $key) {
return strlen($name);
});
$names->toArray();
//[6, 3, 7, 3, 4, 6, 4, 4,]
}
複製程式碼
reduce
不同於 map 和 transform 方法,reduce 方法返回單個值。他將每次迭代的結果傳給下一次迭代。
例如,為了獲取一個集合中所有整數的和,reduce 會傳遞後續數字的總和,並迭代的將結果新增到下一個數字。
/**
* 獲取一個集合中所有數字的和
*/
public function reduceMe()
{
$numbers = collect([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
]);
$sum = $numbers->reduce(function ($sum, $number) {
return $sum + $number;
});
//55
}
複製程式碼
each
each 方法通過回撥函式傳遞每個資料項。
關於 each 方法最有趣的部分是,你可以簡單的在回撥函式中返回 false 來跳出迴圈。
/**
*列印小於等於五的一列數字
*
*/
public function eachMethod()
{
$numbers = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
$smallNumbers = $numbers->each(function ($num, $key) {
if ($num > 5) {
return false;
}
echo $num .", ";
});
//1, 2, 3, 4, 5,
}
複製程式碼
every
every 方法建立一個由集合中每第 n 個元素組成的新集合。
集合論
Laravel 提供了對集合論的支援,這意味著我們可以對兩個不同集合取交集、並集等操作。
union
union
方法將給定的陣列新增到集合。如果給定的陣列含有與原集合一樣的鍵,則原集合的值不會被改變:
/**
* add array values to a collection using union
*/
public function union()
{
$coolPeople = collect([
1 => 'John', 2 => 'James', 3 => 'Jack'
]);
$allCoolPeople = $coolPeople->union([
4 => 'Sarah', 1 => 'Susan', 5 =>'Seyi'
]);
$allCoolPeople->all();
/*
[
1 => "John", 2 => "James", 3 => "Jack", 4 => "Sarah", 5 => "Seyi",
]
*/
}
複製程式碼
intersect
intersect() 方法接收一個陣列或集合作為引數,該方法會將集合中那些不包含在傳入引數的元素移除。
/**
* Return a list of very cool people in collection that
* are in the given array
*/
public function intersect()
{
$coolPeople = collect([
1 => 'John', 2 => 'James', 3 => 'Jack'
]);
$veryCoolPeople = $coolPeople->intersect(['Sarah', 'John', 'James']);
$veryCoolPeople->toArray();
//[1 => "John" 2 => "James"]
}
複製程式碼
可以發現, intersect 方法的返回值保留了原有的鍵。
結論
我試圖涵蓋你可能找到你能自己找到所需的集合方法,但這仍然有太多需要學的。
最值得注意的,我留下以下內容
在 Laravel 文件 和 Laravel API 文件 上還有你可以用於操作集合的更多方法,貨心你想檢視一下。
要跟進本教程程式碼,檢視 gtihub 倉庫 here。隨意貢獻你的程式碼。