简介
Illuminate\Support\Collection 类为处理数据数组提供了一种流畅、便捷的方式。例如,请查看以下代码。我们将使用 collect 辅助函数从数组创建新的集合实例,对每个元素应用 strtoupper 函数,然后移除所有空元素:
$collection = collect(['Taylor', 'Abigail', null])->map(function (?string $name) {
return strtoupper($name);
})->reject(function (string $name) {
return empty($name);
});如您所见,Collection 类允许您链式调用其方法,对底层数组进行流畅的映射和归约操作。通常情况下,集合是不可变的,也就是说,每个 Collection 方法都会返回一个全新的 Collection 实例。
创建集合
如上所述,collect 辅助函数会为给定数组返回一个新的 Illuminate\Support\Collection 实例。因此,创建集合非常简单:
$collection = collect([1, 2, 3]);您也可以使用 make 和 fromJson 方法来创建集合。
Eloquent 查询的结果始终以 Collection 实例的形式返回。
扩展集合
集合是“可使用宏的(macroable)”,这允许您在运行时为 Collection 类添加额外的方法。Illuminate\Support\Collection 类的 macro 方法接受一个闭包,当您的宏被调用时,该闭包将被执行。宏闭包可以通过 $this 访问集合的其他方法,就像它是集合类的真正方法一样。例如,以下代码为 Collection 类添加了一个 toUpper 方法:
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
Collection::macro('toUpper', function () {
return $this->map(function (string $value) {
return Str::upper($value);
});
});
$collection = collect(['first', 'second']);
$upper = $collection->toUpper();
// ['FIRST', 'SECOND']通常,您应该在 服务提供者的 boot 方法中声明集合宏。
宏参数
如果有必要,您可以定义接受额外参数的宏:
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Lang;
Collection::macro('toLocale', function (string $locale) {
return $this->map(function (string $value) use ($locale) {
return Lang::get($value, [], $locale);
});
});
$collection = collect(['first', 'second']);
$translated = $collection->toLocale('es');
// ['primero', 'segundo'];可用方法
对于其余大部分集合文档,我们将讨论 Collection 类中可用的每种方法。请记住,所有这些方法都可以链式调用,以便流畅地操作底层数组。此外,几乎每种方法都会返回一个新的 Collection 实例,允许您在必要时保留集合的原始副本:
after all average avg before chunk chunkBy chunkWhile collapse collapseWithKeys collect combine concat contains containsStrict count countBy crossJoin dd diff diffAssoc diffAssocUsing diffKeys doesntContain doesntContainStrict dot dump duplicates duplicatesStrict each eachSpread ensure every except filter first firstOrFail firstWhere flatMap flatten flip forget forPage fromJson get groupBy has hasAny hasMany hasSole implode intersect intersectUsing intersectAssoc intersectAssocUsing intersectByKeys isEmpty isNotEmpty join keyBy keys last lazy macro make map mapInto mapSpread mapToGroups mapWithKeys max median merge mergeRecursive min mode multiply nth only pad partition percentage pipe pipeInto pipeThrough pluck pop prepend pull push put random range reduce reduceInto reduceSpread reject replace replaceRecursive reverse search select shift shuffle skip skipUntil skipWhile slice sliding sole some sort sortBy sortByDesc sortDesc sortKeys sortKeysDesc sortKeysUsing splice split splitIn sum take takeUntil takeWhile tap times toArray toJson toPrettyJson transform undot union unique uniqueStrict unless unlessEmpty unlessNotEmpty unwrap value values when whenEmpty whenNotEmpty where whereStrict whereBetween whereIn whereInStrict whereInstanceOf whereNotBetween whereNotIn whereNotInStrict whereNotNull whereNull wrap zip
方法列表
after()
after 方法返回指定项之后的项。如果未找到指定项或该项是最后一个项,则返回 null:
$collection = collect([1, 2, 3, 4, 5]);
$collection->after(3);
// 4
$collection->after(5);
// null该方法使用“松散(loose)”比较来搜索给定项,这意味着包含整数值的字符串将被视为与相同值的整数相等。要使用“严格(strict)”比较,您可以向该方法提供 strict 参数:
collect([2, 4, 6, 8])->after('4', strict: true);
// null或者,您可以提供自己的闭包,以搜索第一个通过给定真值测试的项:
collect([2, 4, 6, 8])->after(function (int $item, int $key) {
return $item > 5;
});
// 8all()
all 方法返回集合所表示的底层数组:
collect([1, 2, 3])->all();
// [1, 2, 3]average()
avg 方法的别名。
avg()
avg 方法返回给定键的平均值:
$average = collect([
['foo' => 10],
['foo' => 10],
['foo' => 20],
['foo' => 40]
])->avg('foo');
// 20
$average = collect([1, 1, 2, 4])->avg();
// 2before()
before 方法与 after 方法相反。它返回指定项之前的项。如果未找到指定项或该项是第一个项,则返回 null:
$collection = collect([1, 2, 3, 4, 5]);
$collection->before(3);
// 2
$collection->before(1);
// null
collect([2, 4, 6, 8])->before('4', strict: true);
// null
collect([2, 4, 6, 8])->before(function (int $item, int $key) {
return $item > 5;
});
// 4chunk()
chunk 方法将集合拆分为多个给定大小的较小集合:
$collection = collect([1, 2, 3, 4, 5, 6, 7]);
$chunks = $collection->chunk(4);
$chunks->all();
// [[1, 2, 3, 4], [5, 6, 7]]该方法在视图中配合类似 Bootstrap 的网格系统使用时尤其有用。例如,假设您有一个Eloquent 模型集合,希望以网格形式展示:
@foreach ($products->chunk(3) as $chunk)
<div class="row">
@foreach ($chunk as $product)
<div class="col-xs-4">{{ $product->name }}</div>
@endforeach
</div>
@endforeachchunkBy()
chunkBy 方法通过将给定键或回调具有相同值的相邻项进行分组,将集合拆分为多个较小的集合。例如,您可以将共享相同父级的产品进行相邻分组:
$chunks = $products->chunkBy('parent');与 groupBy 方法不同,具有相同值但不相邻的项会被放入单独的块中:
$collection = collect([1, 1, 2, 2, 1]);
$chunks = $collection->chunkBy(fn (int $value) => $value);
$chunks->all();
// [[1, 1], [2, 2], [1]]chunkWhile()
chunkWhile 方法根据给定回调的评估结果将集合拆分为多个较小的集合。传递给闭包的 $chunk 变量可用于检查前一个元素:
$collection = collect(str_split('AABBCCCD'));
$chunks = $collection->chunkWhile(function (string $value, int $key, Collection $chunk) {
return $value === $chunk->last();
});
$chunks->all();
// [['A', 'A'], ['B', 'B'], ['C', 'C', 'C'], ['D']]collapse()
collapse 方法将数组或集合的集合折叠为单个扁平集合:
$collection = collect([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]);
$collapsed = $collection->collapse();
$collapsed->all();
// [1, 2, 3, 4, 5, 6, 7, 8, 9]collapseWithKeys()
collapseWithKeys 方法将数组或集合的集合扁平化为单个集合,同时保留原始键不变。如果集合已经是扁平的,它将返回一个空集合:
$collection = collect([
['first' => collect([1, 2, 3])],
['second' => [4, 5, 6]],
['third' => collect([7, 8, 9])]
]);
$collapsed = $collection->collapseWithKeys();
$collapsed->all();
// [
// 'first' => [1, 2, 3],
// 'second' => [4, 5, 6],
// 'third' => [7, 8, 9],
// ]collect()
collect 方法返回一个新的 Collection 实例,其中包含集合当前包含的项:
$collectionA = collect([1, 2, 3]);
$collectionB = $collectionA->collect();
$collectionB->all();
// [1, 2, 3]collect 方法主要用于将延迟集合转换为标准的 Collection 实例:
$lazyCollection = LazyCollection::make(function () {
yield 1;
yield 2;
yield 3;
});
$collection = $lazyCollection->collect();
$collection::class;
// 'Illuminate\Support\Collection'
$collection->all();
// [1, 2, 3] 当你有一个 Enumerable 实例,并且需要一个非延迟的集合实例时,collect 方法尤为有用。由于 collect() 是 Enumerable 契约的一部分,你可以安全地使用它来获取一个 Collection 实例。
combine()
combine 方法将集合的值作为键,与另一个数组或集合的值进行组合:
$collection = collect(['name', 'age']);
$combined = $collection->combine(['George', 29]);
$combined->all();
// ['name' => 'George', 'age' => 29]concat()
concat 方法将给定数组或集合的值追加到另一个集合的末尾:
$collection = collect(['John Doe']);
$concatenated = $collection->concat(['Jane Doe'])->concat(['name' => 'Johnny Doe']);
$concatenated->all();
// ['John Doe', 'Jane Doe', 'Johnny Doe']concat 方法会为追加到原始集合的项重新分配数字索引。若要在关联集合中保留键,请参阅 merge 方法。
contains()
contains 方法用于判断集合是否包含给定的项。你可以向 contains 方法传入一个闭包,以判断集合中是否存在满足给定真值测试的元素:
$collection = collect([1, 2, 3, 4, 5]);
$collection->contains(function (int $value, int $key) {
return $value > 5;
});
// false或者,你也可以向 contains 方法传入一个字符串,以判断集合是否包含给定的项值:
$collection = collect(['name' => 'Desk', 'price' => 100]);
$collection->contains('Desk');
// true
$collection->contains('New York');
// false你也可以向 contains 方法传入键 / 值对,该方法会判断集合中是否存在给定的键 / 值对:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->contains('product', 'Bookcase');
// falsecontains 方法在检查项值时采用“松散”比较,这意味着具有整数值的字符串会被视为与相同值的整数相等。若要使用“严格”比较进行筛选,请使用 containsStrict 方法。
若要获取 contains 的相反操作,请参阅 doesntContain 方法。
containsStrict()
该方法与 contains 方法具有相同的签名;不过,所有值均通过“严格”比较进行比较。
在使用 Eloquent Collections 时,该方法的行为会发生变化。
count()
count 方法返回集合中项的总数:
$collection = collect([1, 2, 3, 4]);
$collection->count();
// 4countBy()
countBy 方法用于统计集合中值出现的次数。默认情况下,该方法会统计每个元素的出现次数,从而让你能够统计集合中特定“类型”的元素数量:
$collection = collect([1, 2, 2, 2, 3]);
$counted = $collection->countBy();
$counted->all();
// [1 => 1, 2 => 3, 3 => 1]你可以向 countBy 方法传入一个闭包,以通过自定义值统计所有项:
$collection = collect(['[email protected]', '[email protected]', '[email protected]']);
$counted = $collection->countBy(function (string $email) {
return substr(strrchr($email, '@'), 1);
});
$counted->all();
// ['gmail.com' => 2, 'yahoo.com' => 1]crossJoin()
crossJoin 方法将集合的值与给定的数组或集合进行交叉连接,返回包含所有可能组合的笛卡尔积:
$collection = collect([1, 2]);
$matrix = $collection->crossJoin(['a', 'b']);
$matrix->all();
/*
[
[1, 'a'],
[1, 'b'],
[2, 'a'],
[2, 'b'],
]
*/
$collection = collect([1, 2]);
$matrix = $collection->crossJoin(['a', 'b'], ['I', 'II']);
$matrix->all();
/*
[
[1, 'a', 'I'],
[1, 'a', 'II'],
[1, 'b', 'I'],
[1, 'b', 'II'],
[2, 'a', 'I'],
[2, 'a', 'II'],
[2, 'b', 'I'],
[2, 'b', 'II'],
]
*/dd()
dd 方法会输出集合的项并终止脚本执行:
$collection = collect(['John Doe', 'Jane Doe']);
$collection->dd();
/*
array:2 [
0 => "John Doe"
1 => "Jane Doe"
]
*/若不想终止脚本执行,请改用 dump 方法。
diff()
diff 方法基于值将集合与另一个集合或普通的 PHP array 进行比较。该方法会返回原始集合中不存在于给定集合中的值:
$collection = collect([1, 2, 3, 4, 5]);
$diff = $collection->diff([2, 4, 6, 8]);
$diff->all();
// [1, 3, 5] 在使用 Eloquent Collections 时,该方法的行为会发生变化。
diffAssoc()
diffAssoc 方法基于键和值将集合与另一个集合或普通的 PHP array 进行比较。该方法会返回原始集合中不存在于给定集合中的键 / 值对:
$collection = collect([
'color' => 'orange',
'type' => 'fruit',
'remain' => 6,
]);
$diff = $collection->diffAssoc([
'color' => 'yellow',
'type' => 'fruit',
'remain' => 3,
'used' => 6,
]);
$diff->all();
// ['color' => 'orange', 'remain' => 6]diffAssocUsing()
与 diffAssoc 不同,diffAssocUsing 接受用户提供的回调函数用于索引比较:
$collection = collect([
'color' => 'orange',
'type' => 'fruit',
'remain' => 6,
]);
$diff = $collection->diffAssocUsing([
'Color' => 'yellow',
'Type' => 'fruit',
'Remain' => 3,
], 'strnatcasecmp');
$diff->all();
// ['color' => 'orange', 'remain' => 6]该回调函数必须是一个比较函数,其返回值需为小于、等于或大于零的整数。如需更多信息,请参阅 PHP 关于 array_diff_uassoc 的文档,diffAssocUsing 方法在内部使用的就是该 PHP 函数。
diffKeys()
diffKeys 方法基于键将集合与另一个集合或普通的 PHP array 进行比较。该方法会返回原始集合中不存在于给定集合中的键 / 值对:
$collection = collect([
'one' => 10,
'two' => 20,
'three' => 30,
'four' => 40,
'five' => 50,
]);
$diff = $collection->diffKeys([
'two' => 2,
'four' => 4,
'six' => 6,
'eight' => 8,
]);
$diff->all();
// ['one' => 10, 'three' => 30, 'five' => 50]doesntContain()
doesntContain 方法用于判断集合是否不包含给定的项。你可以向 doesntContain 方法传入一个闭包,以判断集合中是否不存在满足给定真值测试的元素:
$collection = collect([1, 2, 3, 4, 5]);
$collection->doesntContain(function (int $value, int $key) {
return $value < 5;
});
// false或者,你也可以向 doesntContain 方法传入一个字符串,以判断集合中是否不包含给定的项目值:
$collection = collect(['name' => 'Desk', 'price' => 100]);
$collection->doesntContain('Table');
// true
$collection->doesntContain('Desk');
// false你也可以向 doesntContain 方法传入一个键值对,该方法将判断集合中是否不存在给定的键值对:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->doesntContain('product', 'Bookcase');
// true在检查项目值时,doesntContain 方法采用“宽松”比较,即带有整数值的字符串会被视为与相同值的整数相等。
doesntContainStrict()
该方法与 doesntContain 方法具有相同的签名;不过,所有值均采用“严格”比较进行比较。
dot()
dot 方法会将多维集合扁平化为单层集合,并使用“点号”表示法来表示深度:
$collection = collect(['products' => ['desk' => ['price' => 100]]]);
$flattened = $collection->dot();
$flattened->all();
// ['products.desk.price' => 100]dump()
dump 方法会输出集合中的各项内容:
$collection = collect(['John Doe', 'Jane Doe']);
$collection->dump();
/*
array:2 [
0 => "John Doe"
1 => "Jane Doe"
]
*/若想在输出集合内容后停止执行脚本,请改用 dd 方法。
duplicates()
duplicates 方法用于获取并返回集合中的重复值:
$collection = collect(['a', 'b', 'a', 'c', 'b']);
$collection->duplicates();
// [2 => 'a', 4 => 'b']如果集合中包含数组或对象,你可以传入需要检查重复值的属性的键:
$employees = collect([
['email' => '[email protected]', 'position' => 'Developer'],
['email' => '[email protected]', 'position' => 'Designer'],
['email' => '[email protected]', 'position' => 'Developer'],
]);
$employees->duplicates('position');
// [2 => 'Developer']duplicatesStrict()
该方法与 duplicates 方法具有相同的签名;不过,所有值均采用“严格”比较进行比较。
each()
each 方法会遍历集合中的各项,并将每一项传递给一个闭包:
$collection = collect([1, 2, 3, 4]);
$collection->each(function (int $item, int $key) {
// ...
});如果你想停止遍历各项,可在闭包中返回 false:
$collection->each(function (int $item, int $key) {
if (/* condition */) {
return false;
}
});eachSpread()
eachSpread 方法会遍历集合中的各项,并将每个嵌套项的值传递给给定的回调函数:
$collection = collect([['John Doe', 35], ['Jane Doe', 33]]);
$collection->eachSpread(function (string $name, int $age) {
// ...
});你可以在回调函数中返回 false 来停止遍历各项:
$collection->eachSpread(function (string $name, int $age) {
return false;
});ensure()
可以使用 ensure 方法来验证集合中的所有元素是否为给定类型或给定类型列表。否则,将抛出 UnexpectedValueException 异常:
return $collection->ensure(User::class);
return $collection->ensure([User::class, Customer::class]);也可以指定基本类型,例如 string、int、float、bool 和 array:
return $collection->ensure('int'); ensure 方法不能保证之后不会向集合中添加不同类型的元素。
every()
可以使用 every 方法来验证集合中的所有元素是否都通过给定的真值测试:
collect([1, 2, 3, 4])->every(function (int $value, int $key) {
return $value > 2;
});
// false如果集合为空,every 方法将返回 true:
$collection = collect([]);
$collection->every(function (int $value, int $key) {
return $value > 2;
});
// trueexcept()
except 方法会返回集合中除指定键对应的项之外的所有项:
$collection = collect(['product_id' => 1, 'price' => 100, 'discount' => false]);
$filtered = $collection->except(['price', 'discount']);
$filtered->all();
// ['product_id' => 1]关于 except 的相反操作,请参阅 only 方法。
当使用Eloquent 集合(Eloquent Collections)时,该方法的行为会发生改变。
filter()
filter 方法会使用给定的回调函数对集合进行过滤,仅保留通过给定真值测试的项:
$collection = collect([1, 2, 3, 4]);
$filtered = $collection->filter(function (int $value, int $key) {
return $value > 2;
});
$filtered->all();
// [3, 4]若未提供回调函数,则会移除集合中所有等效于 false 的条目:
$collection = collect([1, 2, 3, null, false, '', 0, []]);
$collection->filter()->all();
// [1, 2, 3]关于 filter 的相反操作,请参阅 reject 方法。
first()
first 方法会返回集合中第一个通过给定真值测试的元素:
collect([1, 2, 3, 4])->first(function (int $value, int $key) {
return $value > 2;
});
// 3你也可以在不传入参数的情况下调用 first 方法,以获取集合中的第一个元素。如果集合为空,将返回 null:
collect([1, 2, 3, 4])->first();
// 1firstOrFail()
firstOrFail 方法与 first 方法完全相同;不过,如果未找到结果,将抛出 Illuminate\Support\ItemNotFoundException 异常:
collect([1, 2, 3, 4])->firstOrFail(function (int $value, int $key) {
return $value > 5;
});
// Throws ItemNotFoundException...你也可以在不传入参数的情况下调用 firstOrFail 方法,以获取集合中的第一个元素。如果集合为空,将抛出 Illuminate\Support\ItemNotFoundException 异常:
collect([])->firstOrFail();
// Throws ItemNotFoundException...firstWhere()
firstWhere 方法会返回集合中具有给定键值对的第一个元素:
$collection = collect([
['name' => 'Regena', 'age' => null],
['name' => 'Linda', 'age' => 14],
['name' => 'Diego', 'age' => 23],
['name' => 'Linda', 'age' => 84],
]);
$collection->firstWhere('name', 'Linda');
// ['name' => 'Linda', 'age' => 14]你也可以传入比较运算符来调用 firstWhere 方法:
$collection->firstWhere('age', '>=', 18);
// ['name' => 'Diego', 'age' => 23]与 where 方法一样,你可以向 firstWhere 方法传入一个参数。在这种情况下,firstWhere 方法将返回给定项键的值为“真值”的第一个项:
$collection->firstWhere('age');
// ['name' => 'Linda', 'age' => 14]flatMap()
flatMap 方法会遍历集合,并将每个值传递给给定的闭包。闭包可以修改该项并返回修改后的值,从而形成一个新的包含修改后项的集合。随后,该数组会被扁平化一级:
$collection = collect([
['name' => 'Sally'],
['school' => 'Arkansas'],
['age' => 28]
]);
$flattened = $collection->flatMap(function (array $values) {
return array_map('strtoupper', $values);
});
$flattened->all();
// ['name' => 'SALLY', 'school' => 'ARKANSAS', 'age' => '28'];flatten()
flatten 方法会将多维集合扁平化为一维集合:
$collection = collect([
'name' => 'Taylor',
'languages' => [
'PHP', 'JavaScript'
]
]);
$flattened = $collection->flatten();
$flattened->all();
// ['Taylor', 'PHP', 'JavaScript'];如有必要,你可以为 flatten 方法传入“深度”参数:
$collection = collect([
'Apple' => [
[
'name' => 'iPhone 6S',
'brand' => 'Apple'
],
],
'Samsung' => [
[
'name' => 'Galaxy S7',
'brand' => 'Samsung'
],
],
]);
$products = $collection->flatten(1);
$products->values()->all();
/*
[
['name' => 'iPhone 6S', 'brand' => 'Apple'],
['name' => 'Galaxy S7', 'brand' => 'Samsung'],
]
*/在此示例中,调用 flatten 时若不提供深度参数,也会对嵌套数组进行扁平化处理,结果为 ['iPhone 6S', 'Apple', 'Galaxy S7', 'Samsung']。通过提供深度参数,你可以指定嵌套数组需要被扁平化的层级数。
flip()
flip 方法会交换集合中的键与其对应的值:
$collection = collect(['name' => 'Taylor', 'framework' => 'Laravel']);
$flipped = $collection->flip();
$flipped->all();
// ['Taylor' => 'name', 'Laravel' => 'framework']forget()
forget 方法可根据键移除集合中的某个元素:
$collection = collect(['name' => 'Taylor', 'framework' => 'Laravel']);
// 移除单个键……
$collection->forget('name');
// ['framework' => 'Laravel']
// 移除多个键……
$collection->forget(['name', 'framework']);
// [] 与大多数其他集合方法不同,forget 不会返回一个新的已修改集合;它会修改并返回调用该方法的集合本身。
forPage()
forPage 方法会返回一个新的集合,其中包含指定页码对应的元素。该方法的第一个参数为页码,第二个参数为每页显示的元素数量:
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]);
$chunk = $collection->forPage(2, 3);
$chunk->all();
// [4, 5, 6]fromJson()
静态方法 fromJson 通过 PHP 的 json_decode 函数解码给定的 JSON 字符串,以此创建一个新的集合实例:
use Illuminate\Support\Collection;
$json = json_encode([
'name' => 'Taylor Otwell',
'role' => 'Developer',
'status' => 'Active',
]);
$collection = Collection::fromJson($json);get()
get 方法会返回指定键对应的元素。如果该键不存在,则返回 null:
$collection = collect(['name' => 'Taylor', 'framework' => 'Laravel']);
$value = $collection->get('name');
// Taylor你可以选择性地传入一个默认值作为第二个参数:
$collection = collect(['name' => 'Taylor', 'framework' => 'Laravel']);
$value = $collection->get('age', 34);
// 34你甚至可以将一个回调函数作为该方法的默认值。若指定的键不存在,将返回该回调函数的执行结果:
$collection->get('email', function () {
return '[email protected]';
});
// [email protected]groupBy()
groupBy 方法会根据给定的键对集合中的元素进行分组:
$collection = collect([
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
['account_id' => 'account-x11', 'product' => 'Desk'],
]);
$grouped = $collection->groupBy('account_id');
$grouped->all();
/*
[
'account-x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'account-x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]
*/除了传入字符串类型的 key,你也可以传入一个回调函数。该回调函数应返回你希望用于分组的键值:
$grouped = $collection->groupBy(function (array $item, int $key) {
return substr($item['account_id'], -3);
});
$grouped->all();
/*
[
'x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]
*/可以将多个分组条件以数组的形式传入。数组中的每个元素都会被应用到多维数组对应的层级中:
$data = new Collection([
10 => ['user' => 1, 'skill' => 1, 'roles' => ['Role_1', 'Role_3']],
20 => ['user' => 2, 'skill' => 1, 'roles' => ['Role_1', 'Role_2']],
30 => ['user' => 3, 'skill' => 2, 'roles' => ['Role_1']],
40 => ['user' => 4, 'skill' => 2, 'roles' => ['Role_2']],
]);
$result = $data->groupBy(['skill', function (array $item) {
return $item['roles'];
}], preserveKeys: true);
/*
[
1 => [
'Role_1' => [
10 => ['user' => 1, 'skill' => 1, 'roles' => ['Role_1', 'Role_3']],
20 => ['user' => 2, 'skill' => 1, 'roles' => ['Role_1', 'Role_2']],
],
'Role_3' => [
10 => ['user' => 1, 'skill' => 1, 'roles' => ['Role_1', 'Role_3']],
],
'Role_2' => [
20 => ['user' => 2, 'skill' => 1, 'roles' => ['Role_1', 'Role_2']],
],
],
2 => [
'Role_1' => [
30 => ['user' => 3, 'skill' => 2, 'roles' => ['Role_1']],
],
'Role_2' => [
40 => ['user' => 4, 'skill' => 2, 'roles' => ['Role_2']],
],
],
];
*/has()
has 方法用于判断集合中是否存在指定的键:
$collection = collect(['account_id' => 1, 'product' => 'Desk', 'amount' => 5]);
$collection->has('product');
// true
$collection->has(['product', 'amount']);
// true
$collection->has(['amount', 'price']);
// falsehasAny()
hasAny 方法用于判断集合中是否存在任意一个指定的键:
$collection = collect(['account_id' => 1, 'product' => 'Desk', 'amount' => 5]);
$collection->hasAny(['product', 'price']);
// true
$collection->hasAny(['name', 'price']);
// falsehasMany()
hasMany 方法用于判断集合中是否包含多个元素:
collect([])->hasMany();
// false
collect(['1'])->hasMany();
// false
collect([1, 2, 3])->hasMany();
// true
collect([
['age' => 2],
['age' => 3],
])->hasMany(fn ($item) => $item['age'] === 2);
// falsehasSole()
hasSole 方法用于判断集合中是否仅包含一个元素,可选择性地匹配给定的条件:
collect([])->hasSole();
// false
collect(['1'])->hasSole();
// true
collect([1, 2, 3])->hasSole(fn (int $item) => $item === 2);
// trueimplode()
implode 方法用于拼接集合中的元素。其参数取决于集合中元素的类型。如果集合中包含数组或对象,你应该传入希望拼接的属性对应的键,以及希望在各个值之间插入的“分隔符”字符串:
$collection = collect([
['account_id' => 1, 'product' => 'Desk'],
['account_id' => 2, 'product' => 'Chair'],
]);
$collection->implode('product', ', ');
// 'Desk, Chair'如果集合中包含简单的字符串或数值,你应该仅将“分隔符”作为该方法的参数传入:
collect([1, 2, 3, 4, 5])->implode('-');
// '1-2-3-4-5'如果你希望对参与拼接的值进行格式化,可以为 implode 方法传入一个闭包:
$collection->implode(function (array $item, int $key) {
return strtoupper($item['product']);
}, ', ');
// 'DESK, CHAIR'intersect()
intersect 方法会移除原集合中未出现在给定数组或集合里的值。最终得到的集合将保留原集合的键:
$collection = collect(['Desk', 'Sofa', 'Chair']);
$intersect = $collection->intersect(['Desk', 'Chair', 'Bookcase']);
$intersect->all();
// [0 => 'Desk', 2 => 'Chair']使用 Eloquent 集合(Eloquent Collections)时,该方法的行为会被修改。
intersectUsing()
intersectUsing 方法会使用自定义回调来比较值,从原始集合中移除那些在给定数组或集合中不存在的值。生成的集合将保留原始集合的键:
$collection = collect(['Desk', 'Sofa', 'Chair']);
$intersect = $collection->intersectUsing(['desk', 'chair', 'bookcase'], function (string $a, string $b) {
return strcasecmp($a, $b);
});
$intersect->all();
// [0 => 'Desk', 2 => 'Chair']intersectAssoc()
intersectAssoc 方法会将原始集合与另一个集合或数组进行比较,返回在所有给定集合中都存在的键 / 值对:
$collection = collect([
'color' => 'red',
'size' => 'M',
'material' => 'cotton'
]);
$intersect = $collection->intersectAssoc([
'color' => 'blue',
'size' => 'M',
'material' => 'polyester'
]);
$intersect->all();
// ['size' => 'M']intersectAssocUsing()
intersectAssocUsing 方法会将原始集合与另一个集合或数组进行比较,使用自定义比较回调来比较键,并返回两者中都存在的键 / 值对:
$collection = collect([
'color' => 'red',
'Size' => 'M',
'material' => 'cotton',
]);
$intersect = $collection->intersectAssocUsing([
'color' => 'blue',
'size' => 'M',
'material' => 'polyester',
], function (string $a, string $b) {
return strcasecmp($a, $b);
});
$intersect->all();
// ['Size' => 'M']intersectByKeys()
intersectByKeys 方法会从原始集合中移除那些在给定数组或集合中不存在的键及其对应的值:
$collection = collect([
'serial' => 'UX301', 'type' => 'screen', 'year' => 2009,
]);
$intersect = $collection->intersectByKeys([
'reference' => 'UX404', 'type' => 'tab', 'year' => 2011,
]);
$intersect->all();
// ['type' => 'screen', 'year' => 2009]isEmpty()
如果集合为空,isEmpty 方法返回 true;否则返回 false:
collect([])->isEmpty();
// trueisNotEmpty()
如果集合不为空,isNotEmpty 方法返回 true;否则返回 false:
collect([])->isNotEmpty();
// falsejoin()
join 方法会用字符串将集合的值连接起来。通过该方法的第二个参数,还可以指定最终元素应该如何附加到字符串中:
collect(['a', 'b', 'c'])->join(', '); // 'a, b, c'
collect(['a', 'b', 'c'])->join(', ', ', and '); // 'a, b, and c'
collect(['a', 'b'])->join(', ', ' and '); // 'a and b'
collect(['a'])->join(', ', ' and '); // 'a'
collect([])->join(', ', ' and '); // ''keyBy()
keyBy 方法会以给定的键为集合建立键名。如果多个项具有相同的键,则新集合中只会保留最后一个:
$collection = collect([
['product_id' => 'prod-100', 'name' => 'Desk'],
['product_id' => 'prod-200', 'name' => 'Chair'],
]);
$keyed = $collection->keyBy('product_id');
$keyed->all();
/*
[
'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'],
'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'],
]
*/也可以向该方法传递一个回调函数。该回调函数应返回用于为集合建立键名的值:
$keyed = $collection->keyBy(function (array $item, int $key) {
return strtoupper($item['product_id']);
});
$keyed->all();
/*
[
'PROD-100' => ['product_id' => 'prod-100', 'name' => 'Desk'],
'PROD-200' => ['product_id' => 'prod-200', 'name' => 'Chair'],
]
*/keys()
keys 方法会返回集合的所有键名:
$collection = collect([
'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'],
'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'],
]);
$keys = $collection->keys();
$keys->all();
// ['prod-100', 'prod-200']last()
last 方法会返回集合中最后一个满足给定真值测试的元素:
collect([1, 2, 3, 4])->last(function (int $value, int $key) {
return $value < 3;
});
// 2也可以在调用 last 方法时不传递任何参数,以获取集合中的最后一个元素。如果集合为空,则返回 null:
collect([1, 2, 3, 4])->last();
// 4lazy()
lazy 方法会基于底层的元素数组返回一个新的 LazyCollection 实例:
$lazyCollection = collect([1, 2, 3, 4])->lazy();
$lazyCollection::class;
// Illuminate\Support\LazyCollection
$lazyCollection->all();
// [1, 2, 3, 4]当需要对包含大量元素的庞大 Collection 执行转换操作时,该方法尤为实用:
$count = $hugeCollection
->lazy()
->where('country', 'FR')
->where('balance', '>', '100')
->count();通过将集合转换为 LazyCollection,我们可以避免分配大量额外的内存。尽管原始集合依然会在内存中保留其值,但后续的过滤操作不会。因此,在过滤集合结果时,几乎不会分配额外的内存。
macro()
静态 macro 方法允许在运行时向 Collection 类添加方法。有关更多信息,请参阅关于扩展集合的文档。
make()
静态 make 方法会创建一个新的集合实例。请参阅“创建集合”部分。
use Illuminate\Support\Collection;
$collection = Collection::make([1, 2, 3]);map()
map 方法会遍历集合,并将每个值传递给给定的回调函数。回调函数可以自由修改项并返回它,从而生成一个由修改后的项组成的新集合:
$collection = collect([1, 2, 3, 4, 5]);
$multiplied = $collection->map(function (int $item, int $key) {
return $item * 2;
});
$multiplied->all();
// [2, 4, 6, 8, 10] 与大多数其他集合方法一样,map 会返回一个新的集合实例;它不会修改调用它的集合。如果想要转换原始集合,请使用 transform 方法。
mapInto()
mapInto() 方法会遍历集合,通过将值传递给构造函数来创建给定类的新实例:
class Currency
{
/**
* 创建新的货币实例。
*/
function __construct(
public string $code,
) {}
}
$collection = collect(['USD', 'EUR', 'GBP']);
$currencies = $collection->mapInto(Currency::class);
$currencies->all();
// [Currency('USD'), Currency('EUR'), Currency('GBP')]mapSpread()
mapSpread 方法会遍历集合中的项,将每个嵌套的项值传递给给定的闭包。闭包可以自由修改项并返回它,从而生成一个由修改后的项组成的新集合:
$collection = collect([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
$chunks = $collection->chunk(2);
$sequence = $chunks->mapSpread(function (int $even, int $odd) {
return $even + $odd;
});
$sequence->all();
// [1, 5, 9, 13, 17]mapToGroups()
mapToGroups 方法会根据给定的闭包对集合中的项进行分组。闭包应返回一个包含单个键 / 值对的关联数组,从而生成一个由分组后的值组成的新集合:
$collection = collect([
[
'name' => 'John Doe',
'department' => 'Sales',
],
[
'name' => 'Jane Doe',
'department' => 'Sales',
],
[
'name' => 'Johnny Doe',
'department' => 'Marketing',
]
]);
$grouped = $collection->mapToGroups(function (array $item, int $key) {
return [$item['department'] => $item['name']];
});
$grouped->all();
/*
[
'Sales' => ['John Doe', 'Jane Doe'],
'Marketing' => ['Johnny Doe'],
]
*/
$grouped->get('Sales')->all();
// ['John Doe', 'Jane Doe']mapWithKeys()
mapWithKeys 方法会遍历集合,并将每个值传递给指定的回调函数。该回调函数应返回一个包含单个键/值对的关联数组:
$collection = collect([
[
'name' => 'John',
'department' => 'Sales',
'email' => '[email protected]',
],
[
'name' => 'Jane',
'department' => 'Marketing',
'email' => '[email protected]',
]
]);
$keyed = $collection->mapWithKeys(function (array $item, int $key) {
return [$item['email'] => $item['name']];
});
$keyed->all();
/*
[
'[email protected]' => 'John',
'[email protected]' => 'Jane',
]
*/max()
max 方法会返回指定键的最大值:
$max = collect([
['foo' => 10],
['foo' => 20]
])->max('foo');
// 20
$max = collect([1, 2, 3, 4, 5])->max();
// 5median()
median 方法会返回指定键的中位数值:
$median = collect([
['foo' => 10],
['foo' => 10],
['foo' => 20],
['foo' => 40]
])->median('foo');
// 15
$median = collect([1, 1, 2, 4])->median();
// 1.5merge()
merge 方法会将给定的数组或集合与原集合合并。如果给定项中的字符串键与原集合中的字符串键匹配,则给定项的值会覆盖原集合中的值:
$collection = collect(['product_id' => 1, 'price' => 100]);
$merged = $collection->merge(['price' => 200, 'discount' => false]);
$merged->all();
// ['product_id' => 1, 'price' => 200, 'discount' => false]如果给定项的键是数字键,则其值会被追加到集合的末尾:
$collection = collect(['Desk', 'Chair']);
$merged = $collection->merge(['Bookcase', 'Door']);
$merged->all();
// ['Desk', 'Chair', 'Bookcase', 'Door']mergeRecursive()
mergeRecursive 方法会将给定的数组或集合与原集合递归合并。如果给定项中的字符串键与原集合中的字符串键匹配,则这些键的值会被合并到一个数组中,并且此操作是递归进行的:
$collection = collect(['product_id' => 1, 'price' => 100]);
$merged = $collection->mergeRecursive([
'product_id' => 2,
'price' => 200,
'discount' => false
]);
$merged->all();
// ['product_id' => [1, 2], 'price' => [100, 200], 'discount' => false]min()
min 方法会返回指定键的最小值:
$min = collect([
['foo' => 10],
['foo' => 20]
])->min('foo');
// 10
$min = collect([1, 2, 3, 4, 5])->min();
// 1mode()
mode 方法会返回指定键的众数值:
$mode = collect([
['foo' => 10],
['foo' => 10],
['foo' => 20],
['foo' => 40]
])->mode('foo');
// [10]
$mode = collect([1, 1, 2, 4])->mode();
// [1]
$mode = collect([1, 1, 2, 2])->mode();
// [1, 2]multiply()
multiply 方法会创建指定数量的集合中所有项的副本:
$users = collect([
['name' => 'User #1', 'email' => '[email protected]'],
['name' => 'User #2', 'email' => '[email protected]'],
])->multiply(3);
/*
[
['name' => 'User #1', 'email' => '[email protected]'],
['name' => 'User #2', 'email' => '[email protected]'],
['name' => 'User #1', 'email' => '[email protected]'],
['name' => 'User #2', 'email' => '[email protected]'],
['name' => 'User #1', 'email' => '[email protected]'],
['name' => 'User #2', 'email' => '[email protected]'],
]
*/nth()
nth 方法会创建一个由每第 n 个元素组成的新集合:
$collection = collect(['a', 'b', 'c', 'd', 'e', 'f']);
$collection->nth(4);
// ['a', 'e']你可以选择将起始偏移量作为第二个参数传入:
$collection->nth(4, 1);
// ['b', 'f']only()
only 方法会返回集合中指定键对应的项:
$collection = collect([
'product_id' => 1,
'name' => 'Desk',
'price' => 100,
'discount' => false
]);
$filtered = $collection->only(['product_id', 'name']);
$filtered->all();
// ['product_id' => 1, 'name' => 'Desk']关于 only 的相反操作,请参阅 except 方法。
使用 Eloquent 集合时,该方法的行为会被修改。
pad()
pad 方法会用给定的值填充数组,直到数组达到指定大小。该方法的行为类似于 array_pad PHP 函数。
若要向左填充,应指定一个负数大小。如果给定大小的绝对值小于或等于数组的长度,则不会进行填充:
$collection = collect(['A', 'B', 'C']);
$filtered = $collection->pad(5, 0);
$filtered->all();
// ['A', 'B', 'C', 0, 0]
$filtered = $collection->pad(-5, 0);
$filtered->all();
// [0, 0, 'A', 'B', 'C']partition()
partition 方法可与 PHP 数组解构结合使用,用于将通过给定真值测试的元素与未通过的元素分离开来:
$collection = collect([1, 2, 3, 4, 5, 6]);
[$underThree, $equalOrAboveThree] = $collection->partition(function (int $i) {
return $i < 3;
});
$underThree->all();
// [1, 2]
$equalOrAboveThree->all();
// [3, 4, 5, 6] 与 Eloquent 集合交互时,该方法的行为会被修改。
percentage()
percentage 方法可用于快速确定集合中通过给定真值测试的项所占的百分比:
$collection = collect([1, 1, 2, 2, 2, 3]);
$percentage = $collection->percentage(fn (int $value) => $value === 1);
// 33.33默认情况下,百分比会四舍五入到小数点后两位。不过,你可以向该方法传入第二个参数来自定义此行为:
$percentage = $collection->percentage(fn (int $value) => $value === 1, precision: 3);
// 33.333pipe()
pipe 方法会将集合传递给指定的闭包,并返回所执行闭包的结果:
$collection = collect([1, 2, 3]);
$piped = $collection->pipe(function (Collection $collection) {
return $collection->sum();
});
// 6pipeInto()
pipeInto 方法会创建给定类的新实例,并将集合传入其构造函数:
class ResourceCollection
{
/**
* Create a new ResourceCollection instance.
*/
public function __construct(
public Collection $collection,
) {}
}
$collection = collect([1, 2, 3]);
$resource = $collection->pipeInto(ResourceCollection::class);
$resource->collection->all();
// [1, 2, 3]pipeThrough()
pipeThrough 方法会将集合传递给指定的闭包数组,并返回所执行闭包的结果:
use Illuminate\Support\Collection;
$collection = collect([1, 2, 3]);
$result = $collection->pipeThrough([
function (Collection $collection) {
return $collection->merge([4, 5]);
},
function (Collection $collection) {
return $collection->sum();
},
]);
// 15pluck()
pluck 方法会获取指定键的所有值:
$collection = collect([
['product_id' => 'prod-100', 'name' => 'Desk'],
['product_id' => 'prod-200', 'name' => 'Chair'],
]);
$plucked = $collection->pluck('name');
$plucked->all();
// ['Desk', 'Chair']你也可以指定希望结果集合的键:
$plucked = $collection->pluck('name', 'product_id');
$plucked->all();
// ['prod-100' => 'Desk', 'prod-200' => 'Chair']pluck 方法还支持使用“点”表示法检索嵌套值:
$collection = collect([
[
'name' => 'Laracon',
'speakers' => [
'first_day' => ['Rosa', 'Judith'],
],
],
[
'name' => 'VueConf',
'speakers' => [
'first_day' => ['Abigail', 'Joey'],
],
],
]);
$plucked = $collection->pluck('speakers.first_day');
$plucked->all();
// [['Rosa', 'Judith'], ['Abigail', 'Joey']]如果存在重复的键,则最后一个匹配的元素会被插入到提取后的集合中:
$collection = collect([
['brand' => 'Tesla', 'color' => 'red'],
['brand' => 'Pagani', 'color' => 'white'],
['brand' => 'Tesla', 'color' => 'black'],
['brand' => 'Pagani', 'color' => 'orange'],
]);
$plucked = $collection->pluck('color', 'brand');
$plucked->all();
// ['Tesla' => 'black', 'Pagani' => 'orange']pop()
pop 方法会移除并返回集合中的最后一个元素。如果集合为空,则返回 null:
$collection = collect([1, 2, 3, 4, 5]);
$collection->pop();
// 5
$collection->all();
// [1, 2, 3, 4]你可以向 pop 方法传入一个整数,以从集合末尾移除并返回多个元素:
$collection = collect([1, 2, 3, 4, 5]);
$collection->pop(3);
// collect([5, 4, 3])
$collection->all();
// [1, 2]prepend()
prepend 方法会在集合的开头添加一个元素:
$collection = collect([1, 2, 3, 4, 5]);
$collection->prepend(0);
$collection->all();
// [0, 1, 2, 3, 4, 5]你也可以传入第二个参数,以指定所添加元素的键:
$collection = collect(['one' => 1, 'two' => 2]);
$collection->prepend(0, 'zero');
$collection->all();
// ['zero' => 0, 'one' => 1, 'two' => 2]pull()
pull 方法会根据键从集合中移除并返回一个元素:
$collection = collect(['product_id' => 'prod-100', 'name' => 'Desk']);
$collection->pull('name');
// 'Desk'
$collection->all();
// ['product_id' => 'prod-100']push()
push 方法会将一个元素追加到集合的末尾:
$collection = collect([1, 2, 3, 4]);
$collection->push(5);
$collection->all();
// [1, 2, 3, 4, 5]你也可以传入多个元素,将它们追加到集合的末尾:
$collection = collect([1, 2, 3, 4]);
$collection->push(5, 6, 7);
$collection->all();
// [1, 2, 3, 4, 5, 6, 7]put()
put 方法会在集合中设置给定的键和值:
$collection = collect(['product_id' => 1, 'name' => 'Desk']);
$collection->put('price', 100);
$collection->all();
// ['product_id' => 1, 'name' => 'Desk', 'price' => 100]random()
random 方法会从集合中返回一个随机元素:
$collection = collect([1, 2, 3, 4, 5]);
$collection->random();
// 4 - (retrieved randomly)你可以向 random 传入一个整数,以指定希望随机检索的元素个数。当你显式传入想要获取的元素数量时,总是会返回一个元素集合:
$random = $collection->random(3);
$random->all();
// [2, 4, 5] - (retrieved randomly)如果集合实例中的元素数量少于请求的数量,random 方法会抛出 InvalidArgumentException。
random 方法也接受一个闭包,该闭包会接收当前的集合实例:
use Illuminate\Support\Collection;
$random = $collection->random(fn (Collection $items) => min(10, count($items)));
$random->all();
// [1, 2, 3, 4, 5] - (retrieved randomly)range()
range 方法会返回一个包含指定范围内整数的集合:
$collection = collect()->range(3, 6);
$collection->all();
// [3, 4, 5, 6]reduce()
reduce 方法会将集合归约为一个单一值,并将每次迭代的结果传递给下一次迭代:
$collection = collect([1, 2, 3]);
$total = $collection->reduce(function (?int $carry, int $item) {
return $carry + $item;
});
// 6在第一次迭代时,$carry 的值是 null;不过,你可以通过向 reduce 传入第二个参数来指定其初始值:
$collection->reduce(function (int $carry, int $item) {
return $carry + $item;
}, 4);
// 10reduce 方法也会将数组键传递给给定的回调:
$collection = collect([
'usd' => 1400,
'gbp' => 1200,
'eur' => 1000,
]);
$ratio = [
'usd' => 1,
'gbp' => 1.37,
'eur' => 1.22,
];
$collection->reduce(function (int $carry, int $value, string $key) use ($ratio) {
return $carry + ($value * $ratio[$key]);
}, 0);
// 4264reduceInto()
reduceInto 方法会通过修改给定的初始值,将集合归约为一个单一值。与 reduce 方法不同,给定的回调不需要返回累计值:
class OrderStats
{
public int $total = 0;
public int $count = 0;
}
$orders = collect([
['amount' => 100],
['amount' => 250],
['amount' => 50],
]);
$stats = $orders->reduceInto(new OrderStats, function (OrderStats $stats, array $order) {
$stats->total += $order['amount'];
$stats->count++;
});
$stats->total;
// 400当归约为标量或数组时,你应该在回调中通过引用接收它,这样你的修改才会应用到原始值上:
$collection = collect([1, 2, 3, 4, 5]);
$even = $collection->reduceInto([], function (array &$result, int $value) {
if ($value % 2 === 0) {
$result[] = $value;
}
});
// [2, 4]reduceSpread()
reduceSpread 方法会将集合归约为一个值数组,并将每次迭代的结果传递给下一次迭代。此方法与 reduce 方法相似;不过,它可以接收多个初始值:
[$creditsRemaining, $batch] = Image::where('status', 'unprocessed')
->get()
->reduceSpread(function (int $creditsRemaining, Collection $batch, Image $image) {
if ($creditsRemaining >= $image->creditsRequired()) {
$batch->push($image);
$creditsRemaining -= $image->creditsRequired();
}
return [$creditsRemaining, $batch];
}, $creditsAvailable, collect());reject()
reject 方法会使用给定的闭包对集合进行过滤。如果元素应该从结果集合中移除,则闭包应返回 true:
$collection = collect([1, 2, 3, 4]);
$filtered = $collection->reject(function (int $value, int $key) {
return $value > 2;
});
$filtered->all();
// [1, 2]关于 reject 方法的相反操作,请参阅 filter 方法。
replace()
replace 方法的行为与 merge 类似;不过,除了覆盖具有字符串键的匹配元素外,replace 方法还会覆盖集合中具有匹配数字键的元素:
$collection = collect(['Taylor', 'Abigail', 'James']);
$replaced = $collection->replace([1 => 'Victoria', 3 => 'Finn']);
$replaced->all();
// ['Taylor', 'Victoria', 'James', 'Finn']replaceRecursive()
replaceRecursive 方法的行为与 replace 类似,但它会递归进入数组,并对内部值应用相同的替换过程:
$collection = collect([
'Taylor',
'Abigail',
[
'James',
'Victoria',
'Finn'
]
]);
$replaced = $collection->replaceRecursive([
'Charlie',
2 => [1 => 'King']
]);
$replaced->all();
// ['Charlie', 'Abigail', ['James', 'King', 'Finn']]reverse()
reverse 方法会反转集合中元素的顺序,同时保留原始键:
$collection = collect(['a', 'b', 'c', 'd', 'e']);
$reversed = $collection->reverse();
$reversed->all();
/*
[
4 => 'e',
3 => 'd',
2 => 'c',
1 => 'b',
0 => 'a',
]
*/search()
search 方法会在集合中搜索给定的值,如果找到则返回其键。如果未找到该元素,将返回 false:
$collection = collect([2, 4, 6, 8]);
$collection->search(4);
// 1搜索使用的是“宽松”比较,这意味着具有整数值的字符串会被视为与具有相同值的整数相等。若要使用“严格”比较,请将 true 作为第二个参数传递给该方法:
collect([2, 4, 6, 8])->search('4', strict: true);
// false或者,你也可以提供一个自定义闭包,用于搜索第一个通过给定真值测试的元素:
collect([2, 4, 6, 8])->search(function (int $item, int $key) {
return $item > 5;
});
// 2select()
select 方法从集合中选取给定的键,类似于 SQL 中的 SELECT 语句:
$users = collect([
['name' => 'Taylor Otwell', 'role' => 'Developer', 'status' => 'active'],
['name' => 'Victoria Faith', 'role' => 'Researcher', 'status' => 'active'],
]);
$users->select(['name', 'role']);
/*
[
['name' => 'Taylor Otwell', 'role' => 'Developer'],
['name' => 'Victoria Faith', 'role' => 'Researcher'],
],
*/shift()
shift 方法会移除并返回集合中的首个元素:
$collection = collect([1, 2, 3, 4, 5]);
$collection->shift();
// 1
$collection->all();
// [2, 3, 4, 5]你可以向 shift 方法传入一个整数,以便从集合开头移除并返回多个元素:
$collection = collect([1, 2, 3, 4, 5]);
$collection->shift(3);
// collect([1, 2, 3])
$collection->all();
// [4, 5]shuffle()
shuffle 方法会随机打乱集合中的元素:
$collection = collect([1, 2, 3, 4, 5]);
$shuffled = $collection->shuffle();
$shuffled->all();
// [3, 2, 5, 1, 4] - (generated randomly)skip()
skip 方法会返回一个新的集合,其中已从集合开头移除了指定数量的元素:
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
$collection = $collection->skip(4);
$collection->all();
// [5, 6, 7, 8, 9, 10]skipUntil()
skipUntil 方法会在给定回调返回 false 时跳过集合中的元素。一旦回调返回 true,集合中所有剩余的元素将作为一个新的集合返回:
$collection = collect([1, 2, 3, 4]);
$subset = $collection->skipUntil(function (int $item) {
return $item >= 3;
});
$subset->all();
// [3, 4]你也可以向 skipUntil 方法传入一个简单的值,以便跳过所有元素,直至找到给定的值:
$collection = collect([1, 2, 3, 4]);
$subset = $collection->skipUntil(3);
$subset->all();
// [3, 4] 如果未找到给定的值,或者回调始终返回 false,skipUntil 方法将返回一个空集合。
skipWhile()
skipWhile 方法会在给定回调返回 true 时跳过集合中的元素。一旦回调返回 false,集合中所有剩余的元素将作为一个新的集合返回:
$collection = collect([1, 2, 3, 4]);
$subset = $collection->skipWhile(function (int $item) {
return $item <= 3;
});
$subset->all();
// [4] 如果回调始终不返回 false,skipWhile 方法将返回一个空集合。
slice()
slice 方法会返回从给定索引开始的集合切片:
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
$slice = $collection->slice(4);
$slice->all();
// [5, 6, 7, 8, 9, 10]如果你想要限制返回切片的大小,请将所需的大小作为第二个参数传递给该方法:
$slice = $collection->slice(4, 2);
$slice->all();
// [5, 6]返回的切片默认会保留键。如果你不希望保留原始键,可以使用 values 方法对它们进行重新索引。
sliding()
sliding 方法会返回一个新的元素块集合,这些元素块代表了集合中元素的“滑动窗口”视图:
$collection = collect([1, 2, 3, 4, 5]);
$chunks = $collection->sliding(2);
$chunks->toArray();
// [[1, 2], [2, 3], [3, 4], [4, 5]]这在与 eachSpread 方法结合使用时尤其有用:
$transactions->sliding(2)->eachSpread(function ($previous, $current) {
$current->total = $previous->total + $current->amount;
});你可以选择传入第二个“步长”值,该值用于确定每个元素块中第一个元素之间的距离:
$collection = collect([1, 2, 3, 4, 5]);
$chunks = $collection->sliding(3, step: 2);
$chunks->toArray();
// [[1, 2, 3], [3, 4, 5]]sole()
sole 方法会返回集合中第一个通过给定真值测试的元素,但前提是该真值测试恰好匹配一个元素:
collect([1, 2, 3, 4])->sole(function (int $value, int $key) {
return $value === 2;
});
// 2你也可以向 sole 方法传入一个键 / 值对,该方法会返回集合中第一个匹配给定键值对的元素,但前提是恰好只有一个元素匹配:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->sole('product', 'Chair');
// ['product' => 'Chair', 'price' => 100]或者,如果集合中只有一个元素,你也可以不传入任何参数调用 sole 方法,以获取集合中的第一个元素:
$collection = collect([
['product' => 'Desk', 'price' => 200],
]);
$collection->sole();
// ['product' => 'Desk', 'price' => 200]如果集合中没有元素应通过 sole 方法返回,则会抛出 \Illuminate\Support\ItemNotFoundException 异常。如果有多个元素应被返回,则会抛出 \Illuminate\Support\MultipleItemsFoundException 异常。
some()
contains 方法的别名。
sort()
sort 方法会对集合进行排序。排序后的集合会保留原始的数组键,因此在下面的示例中,我们将使用 values 方法将键重置为连续编号的索引:
$collection = collect([5, 3, 1, 2, 4]);
$sorted = $collection->sort();
$sorted->values()->all();
// [1, 2, 3, 4, 5]如果你的排序需求更为复杂,可以向 sort 传入一个回调函数,以使用你自己的算法。请参阅关于 uasort 的 PHP 文档,集合的 sort 方法内部调用的就是该函数。
如果你需要对包含嵌套数组或对象的集合进行排序,请参阅 sortBy 和 sortByDesc 方法。
sortBy()
sortBy 方法会按照给定的键对集合进行排序。排序后的集合会保留原始的数组键,因此在下面的示例中,我们将使用 values 方法将键重置为连续编号的索引:
$collection = collect([
['name' => 'Desk', 'price' => 200],
['name' => 'Chair', 'price' => 100],
['name' => 'Bookcase', 'price' => 150],
]);
$sorted = $collection->sortBy('price');
$sorted->values()->all();
/*
[
['name' => 'Chair', 'price' => 100],
['name' => 'Bookcase', 'price' => 150],
['name' => 'Desk', 'price' => 200],
]
*/sortBy 方法接受 排序标志作为第二个参数:
$collection = collect([
['title' => 'Item 1'],
['title' => 'Item 12'],
['title' => 'Item 3'],
]);
$sorted = $collection->sortBy('title', SORT_NATURAL);
$sorted->values()->all();
/*
[
['title' => 'Item 1'],
['title' => 'Item 3'],
['title' => 'Item 12'],
]
*/或者,你也可以传入自定义闭包来确定如何对集合中的值进行排序:
$collection = collect([
['name' => 'Desk', 'colors' => ['Black', 'Mahogany']],
['name' => 'Chair', 'colors' => ['Black']],
['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']],
]);
$sorted = $collection->sortBy(function (array $product, int $key) {
return count($product['colors']);
});
$sorted->values()->all();
/*
[
['name' => 'Chair', 'colors' => ['Black']],
['name' => 'Desk', 'colors' => ['Black', 'Mahogany']],
['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']],
]
*/如果你想按多个属性对集合进行排序,可以向 sortBy 方法传入一个排序操作数组。每个排序操作都应是一个数组,包含希望排序的属性以及所需的排序方向:
$collection = collect([
['name' => 'Taylor Otwell', 'age' => 34],
['name' => 'Abigail Otwell', 'age' => 30],
['name' => 'Taylor Otwell', 'age' => 36],
['name' => 'Abigail Otwell', 'age' => 32],
]);
$sorted = $collection->sortBy([
['name', 'asc'],
['age', 'desc'],
]);
$sorted->values()->all();
/*
[
['name' => 'Abigail Otwell', 'age' => 32],
['name' => 'Abigail Otwell', 'age' => 30],
['name' => 'Taylor Otwell', 'age' => 36],
['name' => 'Taylor Otwell', 'age' => 34],
]
*/当按多个属性对集合排序时,你也可以提供闭包来定义每个排序操作:
$collection = collect([
['name' => 'Taylor Otwell', 'age' => 34],
['name' => 'Abigail Otwell', 'age' => 30],
['name' => 'Taylor Otwell', 'age' => 36],
['name' => 'Abigail Otwell', 'age' => 32],
]);
$sorted = $collection->sortBy([
fn (array $a, array $b) => $a['name'] <=> $b['name'],
fn (array $a, array $b) => $b['age'] <=> $a['age'],
]);
$sorted->values()->all();
/*
[
['name' => 'Abigail Otwell', 'age' => 32],
['name' => 'Abigail Otwell', 'age' => 30],
['name' => 'Taylor Otwell', 'age' => 36],
['name' => 'Taylor Otwell', 'age' => 34],
]
*/sortByDesc()
该方法与 sortBy 方法签名一致,但会以相反的顺序对集合进行排序。
sortDesc()
该方法会以与 sort 方法相反的顺序对集合进行排序:
$collection = collect([5, 3, 1, 2, 4]);
$sorted = $collection->sortDesc();
$sorted->values()->all();
// [5, 4, 3, 2, 1]与 sort 不同,你不能向 sortDesc 传入闭包。你应该使用 sort 方法,并反转比较结果。
sortKeys()
sortKeys 方法会按键对底层关联数组进行排序:
$collection = collect([
'id' => 22345,
'first' => 'John',
'last' => 'Doe',
]);
$sorted = $collection->sortKeys();
$sorted->all();
/*
[
'first' => 'John',
'id' => 22345,
'last' => 'Doe',
]
*/sortKeysDesc()
该方法与 sortKeys 方法签名一致,但会以相反的顺序对集合进行排序。
sortKeysUsing()
sortKeysUsing 方法使用回调函数,按键对底层关联数组进行排序:
$collection = collect([
'ID' => 22345,
'first' => 'John',
'last' => 'Doe',
]);
$sorted = $collection->sortKeysUsing('strnatcasecmp');
$sorted->all();
/*
[
'first' => 'John',
'ID' => 22345,
'last' => 'Doe',
]
*/回调函数必须是返回小于、等于或大于零的整数的比较函数。如需了解更多信息,请参阅 PHP 关于 uksort 的文档,sortKeysUsing 方法在内部使用的就是该 PHP 函数。
splice()
splice 方法会移除并返回从指定索引开始的一段元素:
$collection = collect([1, 2, 3, 4, 5]);
$chunk = $collection->splice(2);
$chunk->all();
// [3, 4, 5]
$collection->all();
// [1, 2]你可以传入第二个参数,以限制结果集合的大小:
$collection = collect([1, 2, 3, 4, 5]);
$chunk = $collection->splice(2, 1);
$chunk->all();
// [3]
$collection->all();
// [1, 2, 4, 5]此外,你也可以传入第三个参数,用于存放用于替换被移除元素的新元素:
$collection = collect([1, 2, 3, 4, 5]);
$chunk = $collection->splice(2, 1, [10, 11]);
$chunk->all();
// [3]
$collection->all();
// [1, 2, 10, 11, 4, 5]split()
split 方法会将集合拆分为指定数量的组:
$collection = collect([1, 2, 3, 4, 5]);
$groups = $collection->split(3);
$groups->all();
// [[1, 2], [3, 4], [5]]splitIn()
splitIn 方法会将集合拆分为指定数量的组,在分配剩余元素给最后一组前,会先将非末尾组填满:
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
$groups = $collection->splitIn(3);
$groups->all();
// [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]sum()
sum 方法会返回集合中所有元素的总和:
collect([1, 2, 3, 4, 5])->sum();
// 15如果集合中包含嵌套数组或对象,你应该传入一个键,用于确定要汇总哪些值:
$collection = collect([
['name' => 'JavaScript: The Good Parts', 'pages' => 176],
['name' => 'JavaScript: The Definitive Guide', 'pages' => 1096],
]);
$collection->sum('pages');
// 1272此外,你也可以传入自定义闭包,用于确定要对集合中的哪些值进行汇总:
$collection = collect([
['name' => 'Chair', 'colors' => ['Black']],
['name' => 'Desk', 'colors' => ['Black', 'Mahogany']],
['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']],
]);
$collection->sum(function (array $product) {
return count($product['colors']);
});
// 6take()
take 方法会返回一个新集合,其中包含指定数量的元素:
$collection = collect([0, 1, 2, 3, 4, 5]);
$chunk = $collection->take(3);
$chunk->all();
// [0, 1, 2]你也可以传入负整数,从集合末尾取出指定数量的元素:
$collection = collect([0, 1, 2, 3, 4, 5]);
$chunk = $collection->take(-2);
$chunk->all();
// [4, 5]takeUntil()
takeUntil 方法会返回集合中的元素,直到给定回调返回 true:
$collection = collect([1, 2, 3, 4]);
$subset = $collection->takeUntil(function (int $item) {
return $item >= 3;
});
$subset->all();
// [1, 2]你也可以向 takeUntil 方法传入简单值,以便获取直到找到给定值之前的元素:
$collection = collect([1, 2, 3, 4]);
$subset = $collection->takeUntil(3);
$subset->all();
// [1, 2] 如果未找到给定值,或者回调从未返回 true,takeUntil 方法将返回集合中的所有元素。
takeWhile()
takeWhile 方法会返回集合中的元素,直到给定回调返回 false:
$collection = collect([1, 2, 3, 4]);
$subset = $collection->takeWhile(function (int $item) {
return $item < 3;
});
$subset->all();
// [1, 2] 如果回调从未返回 false,takeWhile 方法将返回集合中的所有元素。
tap()
tap 方法会将集合传递给给定回调,允许你在特定位置“介入”集合,在不影响集合本身的情况下对元素执行操作。随后,tap 方法会返回该集合:
collect([2, 4, 3, 1, 5])
->sort()
->tap(function (Collection $collection) {
Log::debug('Values after sorting', $collection->values()->all());
})
->shift();
// 1times()
静态方法 times 会通过按指定次数调用给定闭包来创建新集合:
$collection = Collection::times(10, function (int $number) {
return $number * 9;
});
$collection->all();
// [9, 18, 27, 36, 45, 54, 63, 72, 81, 90]toArray()
toArray 方法将集合转换为普通的 PHP array。如果集合的值是 Eloquent 模型,这些模型也会被转换为数组:
$collection = collect(['name' => 'Desk', 'price' => 200]);
$collection->toArray();
// ['name' => 'Desk', 'price' => 200] toArray 还会将集合中所有属于 Arrayable 实例的嵌套对象转换为数组。如果你想获取集合底层的原始数组,请改用 all 方法。
toJson()
toJson 方法将集合转换为 JSON 序列化字符串:
$collection = collect(['name' => 'Desk', 'price' => 200]);
$collection->toJson();
// '{"name":"Desk","price":200}'toPrettyJson()
toPrettyJson 方法使用 JSON_PRETTY_PRINT 选项,将集合转换为格式化的 JSON 字符串:
$collection = collect(['name' => 'Desk', 'price' => 200]);
$collection->toPrettyJson();transform()
transform 方法会遍历集合,并使用集合中的每个元素调用给定的回调函数。集合中的元素将被回调函数返回的值替换:
$collection = collect([1, 2, 3, 4, 5]);
$collection->transform(function (int $item, int $key) {
return $item * 2;
});
$collection->all();
// [2, 4, 6, 8, 10] 与大多数其他集合方法不同,transform 会直接修改集合本身。如果你想创建一个新的集合,请使用 map 方法。
undot()
undot 方法将使用“点”表示法的一维集合展开为多维集合:
$person = collect([
'name.first_name' => 'Marie',
'name.last_name' => 'Valentine',
'address.line_1' => '2992 Eagle Drive',
'address.line_2' => '',
'address.suburb' => 'Detroit',
'address.state' => 'MI',
'address.postcode' => '48219'
]);
$person = $person->undot();
$person->toArray();
/*
[
"name" => [
"first_name" => "Marie",
"last_name" => "Valentine",
],
"address" => [
"line_1" => "2992 Eagle Drive",
"line_2" => "",
"suburb" => "Detroit",
"state" => "MI",
"postcode" => "48219",
],
]
*/union()
union 方法将给定的数组合并到集合中。如果给定的数组包含原始集合中已有的键,将优先保留原始集合中的值:
$collection = collect([1 => ['a'], 2 => ['b']]);
$union = $collection->union([3 => ['c'], 1 => ['d']]);
$union->all();
// [1 => ['a'], 2 => ['b'], 3 => ['c']]unique()
unique 方法返回集合中所有的唯一元素。返回的集合会保留原始数组的键,因此在下面的示例中,我们将使用 values 方法将键重置为连续编号的索引:
$collection = collect([1, 1, 2, 2, 3, 4, 2]);
$unique = $collection->unique();
$unique->values()->all();
// [1, 2, 3, 4]在处理嵌套数组或对象时,你可以指定用于判断唯一性的键:
$collection = collect([
['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
['name' => 'iPhone 5', 'brand' => 'Apple', 'type' => 'phone'],
['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'],
['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'],
['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'],
]);
$unique = $collection->unique('brand');
$unique->values()->all();
/*
[
['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'],
]
*/最后,你也可以向 unique 方法传入自定义闭包,以指定哪个值用于判断元素的唯一性:
$unique = $collection->unique(function (array $item) {
return $item['brand'].$item['type'];
});
$unique->values()->all();
/*
[
['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'],
['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'],
['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'],
]
*/unique 方法在检查元素值时会使用“松散”比较,这意味着一个整数值的字符串会被视为与相同值的整数相等。如需使用“严格”比较进行过滤,请使用 uniqueStrict 方法。
使用 Eloquent Collections 时,该方法的行为会发生改变。
uniqueStrict()
该方法的签名与 unique 方法一致;不过,所有值都会使用“严格”比较进行比对。
unless()
unless 方法会在传给该方法的第一个参数求值不为 true 时,执行给定的回调函数。闭包将接收集合实例和传给 unless 方法的第一个参数:
$collection = collect([1, 2, 3]);
$collection->unless(true, function (Collection $collection, bool $value) {
return $collection->push(4);
});
$collection->unless(false, function (Collection $collection, bool $value) {
return $collection->push(5);
});
$collection->all();
// [1, 2, 3, 5]还可以向 unless 方法传入第二个回调函数。当传给 unless 方法的第一个参数求值为 true 时,将执行第二个回调函数:
$collection = collect([1, 2, 3]);
$collection->unless(true, function (Collection $collection, bool $value) {
return $collection->push(4);
}, function (Collection $collection, bool $value) {
return $collection->push(5);
});
$collection->all();
// [1, 2, 3, 5]如需 unless 的反向操作,请参阅 when 方法。
unlessEmpty()
whenNotEmpty 方法的别名。
unlessNotEmpty()
whenEmpty 方法的别名。
unwrap()
静态方法 unwrap 会在适用情况下,从给定值中返回集合底层的元素:
Collection::unwrap(collect('John Doe'));
// ['John Doe']
Collection::unwrap(['John Doe']);
// ['John Doe']
Collection::unwrap('John Doe');
// 'John Doe'value()
value 方法用于从集合的第一个元素中获取给定的值:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Speaker', 'price' => 400],
]);
$value = $collection->value('price');
// 200values()
values 方法返回一个新的集合,并将键重置为连续整数:
$collection = collect([
10 => ['product' => 'Desk', 'price' => 200],
11 => ['product' => 'Speaker', 'price' => 400],
]);
$values = $collection->values();
$values->all();
/*
[
0 => ['product' => 'Desk', 'price' => 200],
1 => ['product' => 'Speaker', 'price' => 400],
]
*/when()
when 方法会在传给该方法的第一个参数求值为 true 时,执行给定的回调函数。闭包将接收集合实例和传给 when 方法的第一个参数:
$collection = collect([1, 2, 3]);
$collection->when(true, function (Collection $collection, bool $value) {
return $collection->push(4);
});
$collection->when(false, function (Collection $collection, bool $value) {
return $collection->push(5);
});
$collection->all();
// [1, 2, 3, 4]还可以向 when 方法传入第二个回调函数。当传给 when 方法的第一个参数求值为 false 时,将执行第二个回调函数:
$collection = collect([1, 2, 3]);
$collection->when(false, function (Collection $collection, bool $value) {
return $collection->push(4);
}, function (Collection $collection, bool $value) {
return $collection->push(5);
});
$collection->all();
// [1, 2, 3, 5]如需 when 的反向操作,请参阅 unless 方法。
whenEmpty()
当集合为空时,whenEmpty 方法会执行给定的回调函数:
$collection = collect(['Michael', 'Tom']);
$collection->whenEmpty(function (Collection $collection) {
return $collection->push('Adam');
});
$collection->all();
// ['Michael', 'Tom']
$collection = collect();
$collection->whenEmpty(function (Collection $collection) {
return $collection->push('Adam');
});
$collection->all();
// ['Adam']可将第二个闭包传递给 whenEmpty 方法,该方法会在集合为空时执行:
$collection = collect(['Michael', 'Tom']);
$collection->whenEmpty(function (Collection $collection) {
return $collection->push('Adam');
}, function (Collection $collection) {
return $collection->push('Taylor');
});
$collection->all();
// ['Michael', 'Tom', 'Taylor']若想了解 whenEmpty 的相反方法,请参阅 whenNotEmpty 方法。
whenNotEmpty()
whenNotEmpty 方法会在集合不为空时执行给定的回调:
$collection = collect(['Michael', 'Tom']);
$collection->whenNotEmpty(function (Collection $collection) {
return $collection->push('Adam');
});
$collection->all();
// ['Michael', 'Tom', 'Adam']
$collection = collect();
$collection->whenNotEmpty(function (Collection $collection) {
return $collection->push('Adam');
});
$collection->all();
// []可将第二个闭包传递给 whenNotEmpty 方法,该方法会在集合为空时执行:
$collection = collect();
$collection->whenNotEmpty(function (Collection $collection) {
return $collection->push('Adam');
}, function (Collection $collection) {
return $collection->push('Taylor');
});
$collection->all();
// ['Taylor']若想了解 whenNotEmpty 的相反方法,请参阅 whenEmpty 方法。
where()
where 方法会根据给定的键/值对对集合进行过滤:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
['product' => 'Bookcase', 'price' => 150],
['product' => 'Door', 'price' => 100],
]);
$filtered = $collection->where('price', 100);
$filtered->all();
/*
[
['product' => 'Chair', 'price' => 100],
['product' => 'Door', 'price' => 100],
]
*/where 方法在检查元素值时使用“松散”比较,这意味着一个值为整数的字符串会被视为与相同值的整数相等。若要使用“严格”比较进行过滤,可使用 whereStrict 方法;若要过滤 null 值,可使用 whereNull 和 whereNotNull 方法。
可选择性地将比较运算符作为第二个参数传入。支持的运算符有:'==='、'!=='、'!='、'=='、'='、'<>'、'>'、'<'、'>=' 和 '<=':
$collection = collect([
['name' => 'Jim', 'platform' => 'Mac'],
['name' => 'Sally', 'platform' => 'Mac'],
['name' => 'Sue', 'platform' => 'Linux'],
]);
$filtered = $collection->where('platform', '!=', 'Linux');
$filtered->all();
/*
[
['name' => 'Jim', 'platform' => 'Mac'],
['name' => 'Sally', 'platform' => 'Mac'],
]
*/whereStrict()
此方法的签名与 where 方法相同;不过,所有值都使用“严格”比较进行比较。
whereBetween()
whereBetween 方法通过判断指定元素的值是否在给定范围内来过滤集合:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 80],
['product' => 'Bookcase', 'price' => 150],
['product' => 'Pencil', 'price' => 30],
['product' => 'Door', 'price' => 100],
]);
$filtered = $collection->whereBetween('price', [100, 200]);
$filtered->all();
/*
[
['product' => 'Desk', 'price' => 200],
['product' => 'Bookcase', 'price' => 150],
['product' => 'Door', 'price' => 100],
]
*/whereIn()
whereIn 方法会从集合中移除那些不包含在给定数组中的指定元素值对应的元素:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
['product' => 'Bookcase', 'price' => 150],
['product' => 'Door', 'price' => 100],
]);
$filtered = $collection->whereIn('price', [150, 200]);
$filtered->all();
/*
[
['product' => 'Desk', 'price' => 200],
['product' => 'Bookcase', 'price' => 150],
]
*/whereIn 方法在检查元素值时使用“松散”比较,这意味着一个值为整数的字符串会被视为与相同值的整数相等。若要使用“严格”比较进行过滤,可使用 whereInStrict 方法。
whereInStrict()
此方法的签名与 whereIn 方法相同;不过,所有值都使用“严格”比较进行比较。
whereInstanceOf()
whereInstanceOf 方法会根据给定的类类型对集合进行过滤:
use App\Models\User;
use App\Models\Post;
$collection = collect([
new User,
new User,
new Post,
]);
$filtered = $collection->whereInstanceOf(User::class);
$filtered->all();
// [App\Models\User, App\Models\User]whereNotBetween()
whereNotBetween 方法通过判断指定元素的值是否在给定范围之外来过滤集合:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 80],
['product' => 'Bookcase', 'price' => 150],
['product' => 'Pencil', 'price' => 30],
['product' => 'Door', 'price' => 100],
]);
$filtered = $collection->whereNotBetween('price', [100, 200]);
$filtered->all();
/*
[
['product' => 'Chair', 'price' => 80],
['product' => 'Pencil', 'price' => 30],
]
*/whereNotIn()
whereNotIn 方法会从集合中移除那些包含在给定数组中的指定元素值对应的元素:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
['product' => 'Bookcase', 'price' => 150],
['product' => 'Door', 'price' => 100],
]);
$filtered = $collection->whereNotIn('price', [150, 200]);
$filtered->all();
/*
[
['product' => 'Chair', 'price' => 100],
['product' => 'Door', 'price' => 100],
]
*/whereNotIn 方法在检查元素值时使用“松散”比较,这意味着一个值为整数的字符串会被视为与相同值的整数相等。若要使用“严格”比较进行过滤,可使用 whereNotInStrict 方法。
whereNotInStrict()
此方法的签名与 whereNotIn 方法相同;不过,所有值都使用“严格”比较进行比较。
whereNotNull()
whereNotNull 方法会返回集合中给定键不为 null 的元素:
$collection = collect([
['name' => 'Desk'],
['name' => null],
['name' => 'Bookcase'],
['name' => 0],
['name' => ''],
]);
$filtered = $collection->whereNotNull('name');
$filtered->all();
/*
[
['name' => 'Desk'],
['name' => 'Bookcase'],
['name' => 0],
['name' => ''],
]
*/whereNull()
whereNull 方法会返回集合中给定键为 null 的元素:
$collection = collect([
['name' => 'Desk'],
['name' => null],
['name' => 'Bookcase'],
['name' => 0],
['name' => ''],
]);
$filtered = $collection->whereNull('name');
$filtered->all();
/*
[
['name' => null],
]
*/wrap()
静态 wrap 方法会在适用的情况下将给定值封装到集合中:
use Illuminate\Support\Collection;
$collection = Collection::wrap('John Doe');
$collection->all();
// ['John Doe']
$collection = Collection::wrap(['John Doe']);
$collection->all();
// ['John Doe']
$collection = Collection::wrap(collect('John Doe'));
$collection->all();
// ['John Doe']zip()
zip 方法会将给定数组的值与原始集合的值在对应的索引处合并在一起:
$collection = collect(['Chair', 'Desk']);
$zipped = $collection->zip([100, 200]);
$zipped->all();
// [['Chair', 100], ['Desk', 200]]高阶消息
集合还支持“高阶消息”,它们是对集合执行常见操作的快捷方式。提供高阶消息的集合方法包括:average、avg、contains、each、every、filter、first、flatMap、groupBy、keyBy、map、max、min、partition、reject、skipUntil、skipWhile、some、sortBy、sortByDesc、sum、takeUntil、takeWhile 和 unique。
每个高阶消息都可以作为集合实例上的动态属性进行访问。例如,我们可以使用 each 高阶消息对集合内的每个对象调用方法:
use App\Models\User;
$users = User::where('votes', '>', 500)->get();
$users->each->markAsVip();同样,我们可以使用 sum 高阶消息来汇总用户集合中“votes”的总数:
$users = User::where('group', 'Development')->get();
return $users->sum->votes;惰性集合
简介
在进一步了解 Laravel 的惰性集合之前,请花些时间熟悉一下 PHP 生成器。
为了补充功能已经十分强大的 Collection 类,LazyCollection 类利用了 PHP 的生成器,让你在处理超大型数据集时仍能保持较低的内存占用。
例如,假设你的应用需要处理一个数吉字节的日志文件,同时又想利用 Laravel 的集合方法来解析日志。与其一次性将整个文件读入内存,不如使用惰性集合,这样在任一时刻只需在内存中保留文件的一小部分:
use App\Models\LogEntry;
use Illuminate\Support\LazyCollection;
LazyCollection::make(function () {
$handle = fopen('log.txt', 'r');
while (($line = fgets($handle)) !== false) {
yield $line;
}
fclose($handle);
})->chunk(4)->map(function (LazyCollection $lines) {
return LogEntry::fromLines($lines);
})->each(function (LogEntry $logEntry) {
// 处理日志条目……
});又或者,假设你需要遍历 10,000 个 Eloquent 模型。当使用传统的 Laravel 集合时,所有 10,000 个 Eloquent 模型都必须同时加载到内存中:
use App\Models\User;
$users = User::all()->filter(function (User $user) {
return $user->id > 500;
});不过,查询构造器的 cursor 方法会返回一个 LazyCollection 实例。这样一来,你仍然只需对数据库执行一次查询,但同时每次只在内存中保留一个 Eloquent 模型。在本示例中,filter 回调并不会执行,直到我们真正逐个遍历每个用户,从而大幅降低内存占用:
use App\Models\User;
$users = User::cursor()->filter(function (User $user) {
return $user->id > 500;
});
foreach ($users as $user) {
echo $user->id;
}创建惰性集合
若要创建一个惰性集合实例,你需要向集合的 make 方法传入一个 PHP 生成器函数:
use Illuminate\Support\LazyCollection;
LazyCollection::make(function () {
$handle = fopen('log.txt', 'r');
while (($line = fgets($handle)) !== false) {
yield $line;
}
fclose($handle);
});Enumerable 契约
Collection 类中提供的几乎所有方法,在 LazyCollection 类中同样可用。这两个类都实现了 Illuminate\Support\Enumerable 契约,该契约定义了以下方法:
allaverageavgchunkchunkBychunkWhilecollapsecollectcombineconcatcontainscontainsStrictcountcountBycrossJoindddiffdiffAssocdiffKeysdumpduplicatesduplicatesStricteacheachSpreadeveryexceptfilterfirstfirstOrFailfirstWhereflatMapflattenflipforPagegetgroupByhasimplodeintersectintersectAssocintersectByKeysisEmptyisNotEmptyjoinkeyBykeyslastmacromakemapmapIntomapSpreadmapToGroupsmapWithKeysmaxmedianmergemergeRecursiveminmodenthonlypadpartitionpipepluckrandomreducereduceIntorejectreplacereplaceRecursivereversesearchshuffleskipslicesolesomesortsortBysortByDescsortKeyssortKeysDescsplitsumtaketaptimestoArraytoJsonunionuniqueuniqueStrictunlessunlessEmptyunlessNotEmptyunwrapvalueswhenwhenEmptywhenNotEmptywherewhereStrictwhereBetweenwhereInwhereInStrictwhereInstanceOfwhereNotBetweenwhereNotInwhereNotInStrictwrapzip
会修改集合的方法(例如 shift、pop、prepend 等)在 LazyCollection 类中是不可用的。
惰性集合方法
除了在 Enumerable 契约中定义的方法之外,LazyCollection 类还包含以下方法:
takeUntilTimeout()
takeUntilTimeout 方法会返回一个新的惰性集合,该集合会持续枚举值直到指定的时间。到该时间后,集合将停止枚举:
$lazyCollection = LazyCollection::times(INF)
->takeUntilTimeout(now()->plus(minutes: 1));
$lazyCollection->each(function (int $number) {
dump($number);
sleep(1);
});
// 1
// 2
// ...
// 58
// 59为了说明该方法的使用场景,设想一个通过游标从数据库提交发票的应用。你可以定义一个每 15 分钟运行一次的计划任务,该任务最多只处理 14 分钟的发票:
use App\Models\Invoice;
use Illuminate\Support\Carbon;
Invoice::pending()->cursor()
->takeUntilTimeout(
Carbon::createFromTimestamp(LARAVEL_START)->add(14, 'minutes')
)
->each(fn (Invoice $invoice) => $invoice->submit());tapEach()
虽然 each 方法会立即为集合中的每个元素调用给定的回调,但 tapEach 方法只会在元素逐个从列表中取出时,才调用给定的回调:
// 到目前为止还没有输出任何内容……
$lazyCollection = LazyCollection::times(INF)->tapEach(function (int $value) {
dump($value);
});
// 三个元素被输出……
$array = $lazyCollection->take(3)->all();
// 1
// 2
// 3throttle()
throttle 方法会对惰性集合进行限流,使得每个值在指定的秒数之后才会被返回。该方法在需要与会对传入请求进行限流的外部 API 进行交互的场景下尤为实用:
use App\Models\User;
User::where('vip', true)
->cursor()
->throttle(seconds: 1)
->each(function (User $user) {
// 调用外部 API……
});remember()
remember 方法会返回一个新的惰性集合,该集合会记住所有已经枚举过的值,并在后续再次枚举集合时不再重新获取这些值:
// 尚未执行任何查询……
$users = User::cursor()->remember();
// 查询被执行……
// 前 5 个用户从数据库中填充……
$users->take(5)->all();
// 前 5 个用户来自集合的缓存……
// 其余用户从数据库中填充……
$users->take(20)->all();withHeartbeat()
withHeartbeat 方法允许你在惰性集合被枚举的过程中,以固定的时间间隔执行回调。这对于需要进行周期性维护任务的长时间运行操作尤为有用,例如延长锁或者发送进度更新:
use Carbon\CarbonInterval;
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('generate-reports', seconds: 60 * 5);
if ($lock->get()) {
try {
Report::where('status', 'pending')
->lazy()
->withHeartbeat(
CarbonInterval::minutes(4),
fn () => $lock->refresh()
)
->each(fn ($report) => $report->process());
} finally {
$lock->release();
}
}