Laravel 13 集合高级操作
Laravel 集合提供了丰富的方法来处理数组数据,本文将深入探讨 Laravel 13 集合的高级操作技巧。
创建集合
基本创建方式
1 2 3 4 5 6 7 8 9 10 11
| use Illuminate\Support\Collection;
$collection = collect([1, 2, 3, 4, 5]);
$collection = Collection::make([1, 2, 3]);
$collection = Collection::times(5, fn ($number) => $number * 2);
$collection = Collection::range(1, 10);
|
从模型创建
1 2
| $users = User::all(); $activeUsers = User::where('active', true)->get();
|
高阶消息传递
高阶方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| $users = User::all();
$users->each->markAsActive(); $users->each(fn ($user) => $user->save());
$names = $users->map->name; $emails = $users->map->email;
$active = $users->filter->isActive(); $admins = $users->filter->isAdmin();
$nonAdmins = $users->reject->isAdmin();
$total = Order::all()->sum->total;
$average = Product::all()->avg->price;
$unique = $users->unique->email;
|
链式操作
复杂链式调用
1 2 3 4 5 6 7
| $result = collect($orders) ->filter(fn ($order) => $order->status === 'completed') ->map(fn ($order) => $order->total) ->reject(fn ($total) => $total <= 0) ->sort() ->take(10) ->values();
|
分组和聚合
groupBy
1 2 3 4 5 6 7 8 9 10 11 12 13
| $users = collect([ ['name' => 'John', 'department' => 'Sales'], ['name' => 'Jane', 'department' => 'Marketing'], ['name' => 'Bob', 'department' => 'Sales'], ]);
$grouped = $users->groupBy('department');
$grouped = $users->groupBy(fn ($user) => strtoupper($user['department'][0]));
|
多级分组
1 2 3 4 5 6 7 8 9 10
| $employees = collect([ ['name' => 'John', 'department' => 'Sales', 'city' => 'NYC'], ['name' => 'Jane', 'department' => 'Sales', 'city' => 'LA'], ['name' => 'Bob', 'department' => 'Marketing', 'city' => 'NYC'], ]);
$grouped = $employees->groupBy([ 'department', fn ($employee) => $employee['city'], ]);
|
keyBy
1 2 3 4 5 6 7
| $users = collect([ ['id' => 1, 'name' => 'John'], ['id' => 2, 'name' => 'Jane'], ]);
$keyed = $users->keyBy('id');
|
聚合方法
1 2 3 4 5 6 7 8 9 10 11 12
| $numbers = collect([1, 2, 3, 4, 5]);
$sum = $numbers->sum(); $avg = $numbers->avg(); $min = $numbers->min(); $max = $numbers->max(); $median = $numbers->median(); $mode = $numbers->mode();
$total = Order::all()->sum->total; $average = Product::all()->avg->price;
|
数据转换
mapWithKeys
1 2 3 4 5 6 7 8 9
| $users = collect([ ['id' => 1, 'name' => 'John'], ['id' => 2, 'name' => 'Jane'], ]);
$pairs = $users->mapWithKeys(fn ($user) => [ $user['id'] => $user['name'] ]);
|
mapInto
1 2 3 4 5 6
| class User { public function __construct(public string $name) {} }
$users = collect(['John', 'Jane', 'Bob'])->mapInto(User::class);
|
mapSpread
1 2 3 4 5 6 7
| $collection = collect([ ['John', 'Doe'], ['Jane', 'Smith'], ]);
$fullNames = $collection->mapSpread(fn ($first, $last) => "$first $last");
|
mapToGroups
1 2 3 4 5 6 7 8 9 10
| $users = collect([ ['name' => 'John', 'role' => 'admin'], ['name' => 'Jane', 'role' => 'user'], ['name' => 'Bob', 'role' => 'admin'], ]);
$grouped = $users->mapToGroups(fn ($user) => [ $user['role'] => $user['name'] ]);
|
pluck
1 2 3 4 5 6 7
| $users = collect([ ['id' => 1, 'name' => 'John', 'email' => 'john@example.com'], ['id' => 2, 'name' => 'Jane', 'email' => 'jane@example.com'], ]);
$names = $users->pluck('name'); $emails = $users->pluck('email', 'id');
|
过滤和搜索
where 条件
1 2 3 4 5 6 7 8 9
| $users = collect([ ['name' => 'John', 'age' => 30, 'active' => true], ['name' => 'Jane', 'age' => 25, 'active' => false], ['name' => 'Bob', 'age' => 35, 'active' => true], ]);
$active = $users->where('active', true); $older = $users->where('age', '>=', 30); $johns = $users->where('name', 'John');
|
whereIn / whereNotIn
1 2
| $filtered = $users->whereIn('age', [25, 30]); $excluded = $users->whereNotIn('age', [35]);
|
whereBetween
1 2
| $inRange = $users->whereBetween('age', [25, 35]); $outRange = $users->whereNotBetween('age', [30, 40]);
|
whereNull / whereNotNull
1 2
| $withEmail = $users->whereNotNull('email'); $withoutEmail = $users->whereNull('email');
|
first / firstWhere / firstOrFail
1 2 3 4
| $first = $users->first(); $john = $users->firstWhere('name', 'John'); $adult = $users->first(fn ($user) => $user['age'] >= 18); $required = $users->firstOrFail(fn ($user) => $user['id'] === 999);
|
search
1 2 3
| $position = collect([1, 2, 3, 4, 5])->search(3); $position = collect(['John', 'Jane'])->search('Jane'); $position = collect([1, 2, 3])->search(fn ($value) => $value > 2);
|
排序
sort / sortBy
1 2 3 4 5 6 7 8 9 10 11 12
| $numbers = collect([3, 1, 4, 1, 5, 9]); $sorted = $numbers->sort(); $desc = $numbers->sortDesc();
$users = collect([ ['name' => 'John', 'age' => 30], ['name' => 'Jane', 'age' => 25], ]);
$byAge = $users->sortBy('age'); $byName = $users->sortBy('name'); $byAgeDesc = $users->sortByDesc('age');
|
多条件排序
1 2 3 4 5 6 7 8 9 10
| $users = collect([ ['name' => 'John', 'age' => 30], ['name' => 'Jane', 'age' => 25], ['name' => 'Bob', 'age' => 30], ]);
$sorted = $users->sortBy([ ['age', 'desc'], ['name', 'asc'], ]);
|
自定义排序
1
| $sorted = $users->sortBy(fn ($a, $b) => $a['age'] <=> $b['age']);
|
分页和分割
chunk
1 2 3 4
| $collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]);
$chunks = $collection->chunk(3);
|
chunkWhile
1 2 3 4
| $collection = collect(['A', 'A', 'B', 'B', 'B', 'C']);
$chunks = $collection->chunkWhile(fn ($value, $key, $chunk) => $value === $chunk->last());
|
split
1 2 3 4
| $collection = collect([1, 2, 3, 4, 5, 6]);
$split = $collection->split(3);
|
partition
1 2 3 4
| $users = collect([1, 2, 3, 4, 5, 6]);
[$even, $odd] = $users->partition(fn ($n) => $n % 2 === 0);
|
take / takeWhile / takeUntil
1 2 3 4 5 6 7
| $collection = collect([1, 2, 3, 4, 5]);
$first3 = $collection->take(3); $last2 = $collection->take(-2);
$takeWhile = $collection->takeWhile(fn ($n) => $n < 4); $takeUntil = $collection->takeUntil(fn ($n) => $n === 4);
|
skip / skipWhile / skipUntil
1 2 3 4 5
| $collection = collect([1, 2, 3, 4, 5]);
$skip2 = $collection->skip(2); $skipWhile = $collection->skipWhile(fn ($n) => $n < 3); $skipUntil = $collection->skipUntil(fn ($n) => $n === 4);
|
集合运算
合并
1 2 3 4 5
| $a = collect([1, 2, 3]); $b = collect([3, 4, 5]);
$merged = $a->merge($b); $union = $a->union($b);
|
交集和差集
1 2 3 4 5 6 7
| $a = collect([1, 2, 3, 4]); $b = collect([3, 4, 5, 6]);
$intersect = $a->intersect($b); $diff = $a->diff($b); $diffAssoc = $a->diffAssoc([1 => 'a', 2 => 'b', 3 => 'c']); $diffKeys = $a->diffKeys([1 => 'a', 5 => 'e']);
|
唯一值
1 2 3 4 5 6 7 8 9 10 11
| $collection = collect([1, 1, 2, 2, 3, 3, 4, 4]); $unique = $collection->unique();
$users = collect([ ['id' => 1, 'name' => 'John'], ['id' => 1, 'name' => 'John'], ['id' => 2, 'name' => 'Jane'], ]);
$unique = $users->unique('id'); $unique = $users->unique(fn ($user) => $user['id'] . $user['name']);
|
数学运算
1 2 3 4 5 6 7 8 9 10 11 12
| $numbers = collect([1, 2, 3, 4, 5]);
$sum = $numbers->sum(); $avg = $numbers->avg(); $min = $numbers->min(); $max = $numbers->max(); $median = $numbers->median(); $mode = $numbers->mode(); $count = $numbers->count();
$sum = $numbers->filter(fn ($n) => $n > 2)->sum();
|
懒惰集合
创建懒惰集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| use Illuminate\Support\LazyCollection;
LazyCollection::make(function () { for ($i = 0; $i < 1000000; $i++) { yield $i; } });
function readLines($path) { $file = fopen($path, 'r'); while ($line = fgets($file)) { yield $line; } fclose($file); }
$lazy = LazyCollection::make(fn () => readLines('large-file.txt'));
|
懒惰集合操作
1 2 3 4 5
| LazyCollection::times(INF) ->take(1000) ->filter(fn ($n) => $n % 2 === 0) ->take(10) ->each(fn ($n) => print($n . PHP_EOL));
|
内存高效处理
1 2 3
| User::cursor() ->filter(fn ($user) => $user->active) ->each(fn ($user) => $user->sendNotification());
|
实用技巧
扁平化嵌套
1 2 3 4 5 6 7
| $nested = collect([ ['name' => 'John', 'tags' => ['php', 'laravel']], ['name' => 'Jane', 'tags' => ['vue', 'react']], ]);
$tags = $nested->pluck('tags')->flatten()->unique();
|
条件执行
1 2 3 4 5 6 7
| $collection = collect([1, 2, 3, 4, 5]);
$result = $collection->when(true, fn ($col) => $col->push(6));
$result = $collection->unless(false, fn ($col) => $col->push(7));
|
管道操作
1 2 3 4
| $result = collect([1, 2, 3, 4, 5]) ->pipe(fn ($collection) => $collection->map(fn ($n) => $n * 2)) ->pipe(fn ($collection) => $collection->filter(fn ($n) => $n > 4));
|
转换为数组和 JSON
1 2 3 4 5
| $collection = collect(['name' => 'John', 'age' => 30]);
$array = $collection->toArray(); $json = $collection->toJson(); $all = $collection->all();
|
最佳实践
1. 使用高阶消息传递简化代码
1 2 3 4 5 6 7
| $users->each->save(); $names = $users->map->name;
$users->each(fn ($user) => $user->save()); $names = $users->map(fn ($user) => $user->name);
|
2. 使用懒惰集合处理大数据
1 2 3 4 5
| User::cursor()->each(fn ($user) => $user->process());
User::all()->each(fn ($user) => $user->process());
|
3. 链式操作保持可读性
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| $result = $orders ->filter(fn ($order) => $order->completed) ->map(fn ($order) => $order->total) ->sum();
$filtered = []; foreach ($orders as $order) { if ($order->completed) { $filtered[] = $order->total; } } $result = array_sum($filtered);
|
总结
Laravel 集合提供了强大且优雅的数据处理能力。通过合理使用高阶消息传递、链式操作、懒惰集合等特性,可以编写出简洁、高效、可读性强的代码。记住在处理大数据集时使用懒惰集合来优化内存使用,并充分利用集合的丰富方法来简化数据处理逻辑。