컬렉션 (Collections)
소개
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
클래스는 메서드 체이닝을 통해 배열을 편리하게 매핑하거나 축소(reduce)할 수 있습니다. 일반적으로 컬렉션은 불변(immutable) 객체로, 모든 Collection
메서드는 전혀 새로운 Collection
인스턴스를 반환합니다.
컬렉션 생성
앞에서 설명한 것처럼, collect
헬퍼는 전달받은 배열로 새로운 Illuminate\Support\Collection
인스턴스를 반환합니다. 따라서 컬렉션을 생성하는 방법은 매우 간단합니다.
$collection = collect([1, 2, 3]);
또한, make 및 fromJson 메서드를 사용하여 컬렉션을 생성할 수도 있습니다.
[!NOTE] Eloquent 쿼리의 결과는 항상
Collection
인스턴스로 반환됩니다.
컬렉션 확장
컬렉션은 "매크로(macro) 기능"을 지원하여 런타임에 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');
사용 가능한 메서드
이후의 컬렉션 관련 문서 대부분은 Collection
클래스에서 제공하는 각 메서드에 대해 다룹니다. 이 모든 메서드는 메서드 체이닝을 통해 배열을 유연하게 조작할 수 있도록 설계되어 있습니다. 또한, 거의 모든 메서드는 새로운 Collection
인스턴스를 반환하므로, 필요에 따라 컬렉션의 원본 데이터를 그대로 보존할 수 있습니다.
after all average avg before chunk chunkWhile collapse collapseWithKeys collect combine concat contains containsOneItem containsStrict count countBy crossJoin dd diff diffAssoc diffAssocUsing diffKeys doesntContain dot dump duplicates duplicatesStrict each eachSpread ensure every except filter first firstOrFail firstWhere flatMap flatten flip forget forPage fromJson get groupBy has hasAny 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 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 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;
});
// 8
all()
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();
// 2
before()
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;
});
// 4
chunk()
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>
@endforeach
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
메서드는 배열이나 컬렉션의 배열로 구성된 컬렉션을 하나의 평면(flat) 컬렉션으로 펼칩니다.
$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]
[!NOTE]
collect
메서드는Enumerable
인스턴스를 가지고 있는데 일반(비-지연) 컬렉션 인스턴스가 필요할 때 특히 유용합니다.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
을 사용할 경우, 추가된 항목의 키는 숫자로 다시 매겨집니다. 연관 배열(associative collection)의 키를 유지하려면 merge 메서드를 참고하세요.
contains()
contains
메서드는 컬렉션에 특정 값이 포함되어 있는지 확인합니다. 클로저를 전달하여, 주어진 조건을 만족하는 요소가 컬렉션에 존재하는지 확인할 수 있습니다.
$collection = collect([1, 2, 3, 4, 5]);
$collection->contains(function (int $value, int $key) {
return $value > 5;
});
// false
또는, 값을 직접 전달해서 해당 값이 존재하는지 확인할 수도 있습니다.
$collection = collect(['name' => 'Desk', 'price' => 100]);
$collection->contains('Desk');
// true
$collection->contains('New York');
// false
키 / 값 쌍을 전달하여 해당 쌍의 존재 여부도 확인할 수 있습니다.
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->contains('product', 'Bookcase');
// false
contains
메서드는 값 비교 시 "느슨한(loose)" 비교를 사용하므로, 정수값이 포함된 문자열도 같은 정수로 간주됩니다. 엄격한(strict) 비교로 필터링하려면 containsStrict 메서드를 사용하세요.
contains
의 반대 동작이 필요하다면 doesntContain 메서드를 참고하세요.
containsOneItem()
containsOneItem
메서드는 컬렉션에 단 하나의 아이템만 존재하는지 확인합니다.
collect([])->containsOneItem();
// false
collect(['1'])->containsOneItem();
// true
collect(['1', '2'])->containsOneItem();
// false
collect([1, 2, 3])->containsOneItem(fn (int $item) => $item === 2);
// true
containsStrict()
이 메서드는 contains 메서드와 동일한 시그니처를 가지지만, 모든 값을 "엄격한(strict)" 비교로 판단합니다.
[!NOTE] 이 메서드는 Eloquent 컬렉션에서 동작 방식이 다르게 동작합니다.
count()
count
메서드는 컬렉션에 포함된 전체 항목의 개수를 반환합니다.
$collection = collect([1, 2, 3, 4]);
$collection->count();
// 4
countBy()
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
메서드는 컬렉션의 값과 지정된 배열 또는 컬렉션을 교차 조합(cross join)하여, 가능한 모든 순열(카르테시안 곱, Cartesian product)을 반환합니다.
$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
메서드는 컬렉션의 항목을 덤프(dump)하고, 이후 스크립트의 실행을 종료합니다.
$collection = collect(['John Doe', 'Jane Doe']);
$collection->dd();
/*
Collection {
#items: 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]
[!NOTE] 이 메서드는 Eloquent 컬렉션에서 동작 방식이 다르게 동작합니다.
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]
콜백 함수는 0보다 작거나, 0이거나, 0보다 큰 정수를 반환하는 비교 함수여야 합니다. 더 자세한 내용은 PHP 공식 문서의 array_diff_uassoc를 참고하세요. diffAssocUsing
메서드는 내부적으로 이 함수에 의존합니다.
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
메서드는 컬렉션에 특정 항목이 존재하지 않는지를 판단합니다. 클로저를 전달하면 주어진 조건(truth test)을 만족시키는 요소가 존재하지 않는지 확인할 수 있습니다.
$collection = collect([1, 2, 3, 4, 5]);
$collection->doesntContain(function (int $value, int $key) {
return $value < 5;
});
// false
또는 단순히 값을 기준으로 존재 여부를 판단하려면 문자열을 전달하면 됩니다.
$collection = collect(['name' => 'Desk', 'price' => 100]);
$collection->doesntContain('Table');
// true
$collection->doesntContain('Desk');
// false
키/값 쌍을 전달하여 해당 쌍이 존재하지 않는지도 확인할 수 있습니다.
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->doesntContain('product', 'Bookcase');
// true
doesntContain
메서드는 항목 값을 비교할 때 "느슨한(loose)" 비교를 사용합니다. 즉, 문자열이 정수형 값으로 변환될 수 있다면, 같은 값으로 간주합니다.
dot()
dot
메서드는 다차원 컬렉션을 "dot" 표기법을 사용하여 깊이를 나타내는 단일 차원의 컬렉션으로 변환합니다.
$collection = collect(['products' => ['desk' => ['price' => 100]]]);
$flattened = $collection->dot();
$flattened->all();
// ['products.desk.price' => 100]
dump()
dump
메서드는 컬렉션의 항목을 출력(dump)합니다.
$collection = collect(['John Doe', 'Jane Doe']);
$collection->dump();
/*
Collection {
#items: 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 메서드와 동일한 시그니처를 갖지만, 모든 값을 "엄격하게(strict)" 비교합니다.
each()
each
메서드는 컬렉션의 각 항목을 반복(iterate)하면서, 각 항목을 클로저에 전달합니다.
$collection = collect([1, 2, 3, 4]);
$collection->each(function (int $item, int $key) {
// ...
});
반복을 도중에 중지하고 싶으면, 클로저에서 false
를 반환하면 됩니다.
$collection->each(function (int $item, int $key) {
if (/* 조건 */) {
return false;
}
});
eachSpread()
eachSpread
메서드는 컬렉션의 각 항목(중첩 배열일 경우 내부 값들)을 펼쳐서(spread) 콜백 함수에 각각 전달하며 반복합니다.
$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');
[!WARNING]
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;
});
// true
except()
except
메서드는 지정한 키를 제외한 나머지 항목만을 포함하는 새로운 컬렉션을 반환합니다.
$collection = collect(['product_id' => 1, 'price' => 100, 'discount' => false]);
$filtered = $collection->except(['price', 'discount']);
$filtered->all();
// ['product_id' => 1]
except
메서드와 반대로 동작하는 것은 only 메서드입니다.
[!NOTE] 이 메서드는 Eloquent 컬렉션에서 동작 방식이 다르게 동작합니다.
filter()
filter
메서드는 주어진 콜백 함수를 이용해 컬렉션을 필터링한 결과만을 남겨 새로운 컬렉션을 만듭니다(조건을 만족하는 항목만 유지).
$collection = collect([1, 2, 3, 4]);
$filtered = $collection->filter(function (int $value, int $key) {
return $value > 2;
});
$filtered->all();
// [3, 4]
콜백을 전달하지 않으면, PHP에서 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
아무런 인수 없이 호출하면, 컬렉션의 첫 번째 요소를 반환합니다. 컬렉션이 비어 있으면 null
을 반환합니다.
collect([1, 2, 3, 4])->first();
// 1
firstOrFail()
firstOrFail
메서드는 first
메서드와 동일하지만, 조건을 만족하는 결과가 없을 경우 Illuminate\Support\ItemNotFoundException
예외를 발생시킵니다.
collect([1, 2, 3, 4])->firstOrFail(function (int $value, int $key) {
return $value > 5;
});
// Throws ItemNotFoundException...
인수를 전달하지 않고 호출하면 컬렉션의 첫 번째 요소를 반환합니다. 컬렉션이 비어 있으면 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]
비교 연산자를 같이 전달할 수도 있습니다.
$collection->firstWhere('age', '>=', 18);
// ['name' => 'Diego', 'age' => 23]
where 메서드와 마찬가지로, 키만 전달하면 해당 키 값이 truthy(참)인 첫 번째 값을 반환합니다.
$collection->firstWhere('age');
// ['name' => 'Linda', 'age' => 14]
flatMap()
flatMap
메서드는 각 요소를 클로저에 전달하여, 원하는 값을 반환하도록 변환한 다음, 그 결과를 한 단계만 평탄화(flat)하여 새로운 컬렉션을 만듭니다.
$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'];
필요하다면 평탄화할 "깊이"를 인수로 지정할 수도 있습니다.
$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']);
// []
[!WARNING] 대부분의 다른 컬렉션 메서드와 달리,
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
은 주어진 JSON 문자열을 PHP의 json_decode
함수를 사용해 디코딩하여 새로운 컬렉션 인스턴스를 생성합니다.
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'],
],
]
*/
문자열 키 대신 콜백을 전달할 수도 있습니다. 이 콜백의 반환값으로 그룹의 키가 정해집니다.
$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_2' => [
20 => ['user' => 2, 'skill' => 1, 'roles' => ['Role_1', 'Role_2']],
],
'Role_3' => [
10 => ['user' => 1, 'skill' => 1, 'roles' => ['Role_1', 'Role_3']],
],
],
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']);
// false
hasAny()
hasAny
메서드는 전달한 키들 중 하나라도 컬렉션에 존재하는지 판단합니다.
$collection = collect(['account_id' => 1, 'product' => 'Desk', 'amount' => 5]);
$collection->hasAny(['product', 'price']);
// true
$collection->hasAny(['name', 'price']);
// false
implode()
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']
[!NOTE] Eloquent 컬렉션을 사용할 경우, 이 메서드의 동작이 달라질 수 있습니다.
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();
// true
isNotEmpty()
isNotEmpty
메서드는 컬렉션이 비어 있지 않으면 true
를, 비어 있다면 false
를 반환합니다.
collect([])->isNotEmpty();
// false
join()
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
인수 없이 호출하면 컬렉션의 마지막 요소를 반환합니다. 컬렉션이 비어 있다면 null
이 반환됩니다.
collect([1, 2, 3, 4])->last();
// 4
lazy()
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]
[!WARNING] 대부분의 컬렉션 메서드처럼,
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();
// 5
median()
median
메서드는 지정한 키에 대해 중앙값(median)을 반환합니다.
$median = collect([
['foo' => 10],
['foo' => 10],
['foo' => 20],
['foo' => 40]
])->median('foo');
// 15
$median = collect([1, 1, 2, 4])->median();
// 1.5
merge()
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();
// 1
mode()
mode
메서드는 지정한 키에 대해 최빈값(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 메서드를 참고하시기 바랍니다.
[!NOTE] 이 메서드는 Eloquent 컬렉션 사용 시 동작이 변경될 수 있습니다.
pad()
pad
메서드는 컬렉션의 길이가 지정한 크기에 도달할 때까지 주어진 값으로 채웁니다. 이 메서드는 PHP의 array_pad 함수와 유사하게 동작합니다.
왼쪽으로 값을 채우려면 음수 크기를 지정하면 됩니다. 만약 지정한 절댓값이 컬렉션 길이보다 작거나 같으면 패딩은 적용되지 않습니다.
$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의 배열 비구조화(destructuring)와 함께 사용하여, 조건에 맞는 요소와 맞지 않는 요소들을 각각 분리할 수 있습니다.
$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]
[!NOTE] 이 메서드는 Eloquent 컬렉션과 함께 사용할 때 동작이 다를 수 있습니다.
percentage()
percentage
메서드는 컬렉션에서 주어진 조건을 만족하는 항목의 비율(%)을 빠르게 구할 수 있도록 도와줍니다.
$collection = collect([1, 1, 2, 2, 2, 3]);
$percentage = $collection->percentage(fn (int $value) => $value === 1);
// 33.33
기본적으로 소수점 둘째 자리까지 반올림하여 반환하지만, 두 번째 인수로 원하는 정밀도(precision)를 지정해 동작을 변경할 수 있습니다.
$percentage = $collection->percentage(fn (int $value) => $value === 1, precision: 3);
// 33.333
pipe()
pipe
메서드는 컬렉션을 주어진 클로저에 전달하고, 그 클로저의 실행 결과를 반환합니다.
$collection = collect([1, 2, 3]);
$piped = $collection->pipe(function (Collection $collection) {
return $collection->sum();
});
// 6
pipeInto()
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();
},
]);
// 15
pluck()
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
메서드는 "dot" 표기법을 이용해 중첩된 값도 추출할 수 있습니다.
$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']]
만약 중복된 키가 있다면, pluck
된 컬렉션에는 마지막 요소가 저장됩니다.
$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
메서드는 컬렉션의 마지막 항목을 제거하고 그 항목을 반환합니다.
$collection = collect([1, 2, 3, 4, 5]);
$collection->pop();
// 5
$collection->all();
// [1, 2, 3, 4]
정수를 인수로 전달하면, 컬렉션의 끝에서 여러 항목을 한 번에 제거해 반환할 수 있습니다.
$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]
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 - (랜덤하게 추출됨)
random
에 정수를 전달하면 원하는 수만큼 임의의 항목들을 반환합니다. 반환값은 항상 컬렉션 형태입니다.
$random = $collection->random(3);
$random->all();
// [2, 4, 5] - (랜덤하게 추출됨)
컬렉션에 요청한 개수보다 적은 항목만 있을 경우, random
메서드는 InvalidArgumentException
을 발생시킵니다.
또한, 현재 컬렉션 인스턴스를 인자로 받는 클로저를 전달할 수도 있습니다.
use Illuminate\Support\Collection;
$random = $collection->random(fn (Collection $items) => min(10, count($items)));
$random->all();
// [1, 2, 3, 4, 5] - (랜덤하게 추출됨)
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
입니다. 다만, 두 번째 인수로 초기값을 지정할 수도 있습니다.
$collection->reduce(function (int $carry, int $item) {
return $carry + $item;
}, 4);
// 10
reduce
메서드는 콜백에 배열 키도 함께 전달합니다.
$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);
// 4264
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
와 유사하게 동작합니다. 하지만 문자열 키뿐 아니라 일치하는 숫자 키까지 기존 값에 덮어씁니다.
$collection = collect(['Taylor', 'Abigail', 'James']);
$replaced = $collection->replace([1 => 'Victoria', 3 => 'Finn']);
$replaced->all();
// ['Taylor', 'Victoria', 'James', 'Finn']
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
검색은 "느슨한(loose)" 비교로 진행되기 때문에, 정수 값인 문자열과 정수 값이 같으면 동일하게 간주됩니다. "엄격한(strict)" 비교를 원한다면 두 번째 인수로 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;
});
// 2
select()
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]
정수를 인수로 전달하면, 컬렉션의 앞부분에서 여러 항목을 제거해 반환합니다.
$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] - (랜덤하게 재배열됨)
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]
또한, 간단한 값을 전달하면 해당 값을 만날 때까지 항목을 건너뜁니다.
$collection = collect([1, 2, 3, 4]);
$subset = $collection->skipUntil(3);
$subset->all();
// [3, 4]
[!WARNING] 지정한 값이 없거나 콜백이 한 번도
true
를 반환하지 않으면,skipUntil
메서드는 빈 컬렉션을 반환합니다.
skipWhile()
skipWhile
메서드는 주어진 콜백이 true
를 반환하는 동안 컬렉션을 건너뜁니다. 콜백이 false
를 반환하는 시점부터 남은 모든 항목을 새로운 컬렉션으로 반환합니다.
$collection = collect([1, 2, 3, 4]);
$subset = $collection->skipWhile(function (int $item) {
return $item <= 3;
});
$subset->all();
// [4]
[!WARNING] 콜백이 한 번도
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]
반환된 슬라이스는 기본적으로 키를 유지합니다. 원래의 키를 재정렬(reindex)하려면 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 (Collection $previous, Collection $current) {
$current->total = $previous->total + $current->amount;
});
두 번째 "step" 값을 추가로 전달할 수 있습니다. 이 값은 각 청크의 첫 번째 항목 간의 거리를 결정합니다.
$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
키와 값을 한 쌍으로 전달하여, 정확히 한 항목만 일치하는 경우 해당 항목을 반환할 수도 있습니다.
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->sole('product', 'Chair');
// ['product' => 'Chair', 'price' => 100]
인수를 전달하지 않으면, 컬렉션에 항목이 단 하나만 있을 때 해당 항목을 반환합니다.
$collection = collect([
['product' => 'Desk', 'price' => 200],
]);
$collection->sole();
// ['product' => 'Desk', 'price' => 200]
반환할 항목이 없으면 \Illuminate\Collections\ItemNotFoundException
예외가 발생합니다. 두 개 이상이 일치할 경우 \Illuminate\Collections\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
는 PHP의 uasort를 사용합니다.
[!NOTE] 중첩 배열이나 객체 컬렉션을 정렬할 때는 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',
]
*/
이때 콜백은 비교 함수여야 하며, 두 값을 받아 0보다 작거나, 같거나, 크거나 한 정수를 반환해야 합니다. 더 자세한 내용은 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']);
});
// 6
take()
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]
또한, 간단하게 값을 전달하여 해당 값이 나올 때까지의 항목을 반환할 수도 있습니다.
$collection = collect([1, 2, 3, 4]);
$subset = $collection->takeUntil(3);
$subset->all();
// [1, 2]
[!WARNING] 전달한 값이 컬렉션에서 찾을 수 없거나, 콜백이 한 번도
true
를 반환하지 않으면takeUntil
메서드는 컬렉션의 모든 항목을 반환합니다.
takeWhile()
takeWhile
메서드는 지정한 콜백이 false
를 반환할 때까지의 항목들을 반환합니다.
$collection = collect([1, 2, 3, 4]);
$subset = $collection->takeWhile(function (int $item) {
return $item < 3;
});
$subset->all();
// [1, 2]
[!WARNING] 콜백이 한 번도
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();
// 1
times()
정적(static) 메서드인 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],
]
*/
[!WARNING]
toArray
는 컬렉션 내의 모든 중첩 객체 중Arrayable
인터페이스를 구현한 객체도 배열로 변환합니다. 컬렉션이 감싸고 있는 원본 배열 자체를 반환하고 싶다면 all 메서드를 사용하세요.
toJson()
toJson
메서드는 컬렉션을 JSON 직렬화된 문자열로 변환합니다.
$collection = collect(['name' => 'Desk', 'price' => 200]);
$collection->toJson();
// '{"name":"Desk", "price":200}'
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]
[!WARNING] 대부분의 다른 컬렉션 메서드와 달리,
transform
은 컬렉션 자체를 직접 변경합니다. 만약 새로운 컬렉션을 만들고 싶다면 map 메서드를 사용하세요.
undot()
undot
메서드는 "dot" 표기법을 사용한 1차원 배열 형태의 컬렉션을 다차원 컬렉션으로 확장합니다.
$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
메서드는 항목 값을 비교할 때 "느슨한(loose)" 비교를 사용하므로, 예를 들어 문자열로 된 숫자와 정수 값이 같으면 같은 값으로 간주됩니다. "엄격한(strict)" 비교를 하고 싶다면 uniqueStrict 메서드를 사용하세요.
[!NOTE] Eloquent 컬렉션을 사용할 때는 이 메서드의 동작이 다르게 동작할 수 있습니다.
uniqueStrict()
이 메서드는 unique 메서드와 동일한 시그니처를 가지며, 값 비교 방식만 "엄격한(strict)" 비교로 처리합니다.
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]
또한 두 번째 콜백을 전달하면 첫 번째 인자가 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');
// 200
values()
values
메서드는 키를 0부터 시작하는 연속된 정수로 재설정한 새로운 컬렉션을 반환합니다.
$collection = collect([
10 => ['product' => 'Desk', 'price' => 200],
11 => ['product' => 'Desk', 'price' => 200],
]);
$values = $collection->values();
$values->all();
/*
[
0 => ['product' => 'Desk', 'price' => 200],
1 => ['product' => 'Desk', 'price' => 200],
]
*/
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
메서드에 두 번째 콜백을 전달할 수 있습니다. 이 두 번째 콜백은 첫 번째 인자가 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']
또한 컬렉션이 비어 있지 않을 때 실행되는 두 번째 클로저를 전달할 수도 있습니다.
$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();
// []
또한 컬렉션이 비어 있을 때 실행되는 두 번째 클로저를 전달할 수도 있습니다.
$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
메서드는 값 비교 시 "느슨한(loose)" 비교를 사용합니다. 즉, 정수형 값과 동일한 값을 가진 문자열은 동일하다고 간주합니다. "엄격한(strict)" 비교를 원할 경우 whereStrict 메서드를 사용하세요.
선택적으로, 두 번째 인자로 비교 연산자를 전달할 수 있습니다. 지원되는 연산자는 다음과 같습니다: ===
, !==
, !=
, ==
, =
, <>
, >
, <
, >=
, <=
$collection = collect([
['name' => 'Jim', 'deleted_at' => '2019-01-01 00:00:00'],
['name' => 'Sally', 'deleted_at' => '2019-01-02 00:00:00'],
['name' => 'Sue', 'deleted_at' => null],
]);
$filtered = $collection->where('deleted_at', '!=', null);
$filtered->all();
/*
[
['name' => 'Jim', 'deleted_at' => '2019-01-01 00:00:00'],
['name' => 'Sally', 'deleted_at' => '2019-01-02 00:00:00'],
]
*/
whereStrict()
이 메서드는 where 메서드와 동일한 시그니처를 가지지만, 모든 값을 "엄격한(strict)" 방식으로 비교합니다.
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
메서드 역시 값 비교 시 "느슨한(loose)" 비교를 사용합니다. 즉, 정수형 값과 동일한 값을 가진 문자열도 일치합니다. "엄격한(strict)" 비교를 원할 경우 whereInStrict 메서드를 사용하세요.
whereInStrict()
이 메서드는 whereIn 메서드와 동일한 시그니처를 가지지만, 모든 값을 "엄격한(strict)" 방식으로 비교합니다.
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
메서드 역시 값 비교 시 "느슨한(loose)" 비교를 사용합니다. 즉, 정수형 값과 동일한 값을 가진 문자열도 일치합니다. "엄격한(strict)" 비교를 원할 경우 whereNotInStrict 메서드를 사용하세요.
whereNotInStrict()
이 메서드는 whereNotIn 메서드와 동일한 시그니처를 가지지만, 모든 값을 "엄격한(strict)" 방식으로 비교합니다.
whereNotNull()
whereNotNull
메서드는 주어진 키가 null
이 아닌 항목들만 반환합니다.
$collection = collect([
['name' => 'Desk'],
['name' => null],
['name' => 'Bookcase'],
]);
$filtered = $collection->whereNotNull('name');
$filtered->all();
/*
[
['name' => 'Desk'],
['name' => 'Bookcase'],
]
*/
whereNull()
whereNull
메서드는 주어진 키가 null
인 항목들만 반환합니다.
$collection = collect([
['name' => 'Desk'],
['name' => null],
['name' => 'Bookcase'],
]);
$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]]
하이어 오더 메시지(Higher Order Messages)
컬렉션은 "하이어 오더 메시지"도 지원합니다. 이는 컬렉션에서 자주 사용하는 행동을 간략하게 수행할 수 있도록 해주는 단축 메서드입니다. 하이어 오더 메시지를 제공하는 컬렉션 메서드는 다음과 같습니다: 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;
레이지 컬렉션(Lazy Collections)
소개
[!WARNING] 라라벨의 레이지 컬렉션을 더 알아보기 전에, PHP 제너레이터에 먼저 익숙해지는 것을 권장합니다.
이미 강력한 Collection
클래스에 더해, LazyCollection
클래스는 PHP의 제너레이터(generator)를 활용해 메모리 사용을 최소화하며 아주 큰 데이터셋을 다룰 수 있게 해줍니다.
예를 들어, 애플리케이션에서 여러 GB에 달하는 대용량 로그 파일을 라라벨의 컬렉션 메서드를 활용해 처리해야 한다고 가정해보겠습니다. 전체 파일을 한 번에 메모리에 올리는 대신, 레이지 컬렉션을 사용하면 한 번에 파일의 작은 부분만 메모리에 유지하면서 작업할 수 있습니다.
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 (array $lines) {
return LogEntry::fromLines($lines);
})->each(function (LogEntry $logEntry) {
// 로그 항목 처리...
});
또한, 10,000개의 Eloquent 모델을 반복적으로 탐색해야 할 때를 생각해봅시다. 기존 라라벨 컬렉션을 사용하면 이 모든 모델을 한 번에 메모리에 로드해야 합니다.
use App\Models\User;
$users = User::all()->filter(function (User $user) {
return $user->id > 500;
});
하지만, 쿼리 빌더의 cursor
메서드는 LazyCollection
인스턴스를 반환합니다. 덕분에 데이터베이스 쿼리는 한 번만 실행되고, 메모리에는 한 번에 Eloquent 모델 하나만 남게 됩니다. 아래 예시에서는 실제로 각 사용자를 반복(iterate)하기 전까지 filter
콜백이 실행되지 않으므로, 메모리 사용량이 획기적으로 줄어듭니다.
use App\Models\User;
$users = User::cursor()->filter(function (User $user) {
return $user->id > 500;
});
foreach ($users as $user) {
echo $user->id;
}
레이지 컬렉션 생성하기
레이지 컬렉션 인스턴스를 생성하려면, PHP 제너레이터 함수를 컬렉션의 make
메서드에 전달하면 됩니다.
use Illuminate\Support\LazyCollection;
LazyCollection::make(function () {
$handle = fopen('log.txt', 'r');
while (($line = fgets($handle)) !== false) {
yield $line;
}
fclose($handle);
});
Enumerable 계약(Contract)
Collection
클래스에서 제공하는 거의 모든 메서드를 LazyCollection
클래스에서도 사용할 수 있습니다. 이 두 클래스는 모두 Illuminate\Support\Enumerable
계약을 구현하며, 해당 계약에는 다음과 같은 메서드들이 정의되어 있습니다.
all average avg chunk chunkWhile collapse collect combine concat contains containsStrict count countBy crossJoin dd diff diffAssoc diffKeys dump duplicates duplicatesStrict each eachSpread every except filter first firstOrFail firstWhere flatMap flatten flip forPage get groupBy has implode intersect intersectAssoc intersectByKeys isEmpty isNotEmpty join keyBy keys last macro make map mapInto mapSpread mapToGroups mapWithKeys max median merge mergeRecursive min mode nth only pad partition pipe pluck random reduce reject replace replaceRecursive reverse search shuffle skip slice sole some sort sortBy sortByDesc sortKeys sortKeysDesc split sum take tap times toArray toJson union unique uniqueStrict unless unlessEmpty unlessNotEmpty unwrap values when whenEmpty whenNotEmpty where whereStrict whereBetween whereIn whereInStrict whereInstanceOf whereNotBetween whereNotIn whereNotInStrict wrap zip
[!WARNING] 컬렉션을 변형(변이)하는 메서드(
shift
,pop
,prepend
등)는LazyCollection
클래스에서 지원되지 않습니다.
지연 컬렉션 메서드
Enumerable
계약(Contract)에 정의된 메서드 외에도, LazyCollection
클래스는 다음과 같은 메서드를 제공합니다.
takeUntilTimeout()
takeUntilTimeout
메서드는 지정한 시간까지 값을 반환하는 새로운 지연 컬렉션을 만듭니다. 해당 시간이 지나면 컬렉션의 값 반환이 중지됩니다.
$lazyCollection = LazyCollection::times(INF)
->takeUntilTimeout(now()->addMinute());
$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
메서드는 항목이 하나씩 컬렉션에서 꺼내질 때마다 콜백을 실행합니다.
// 아직 아무것도 dump되지 않았습니다...
$lazyCollection = LazyCollection::times(INF)->tapEach(function (int $value) {
dump($value);
});
// 세 개의 값만 dump됩니다...
$array = $lazyCollection->take(3)->all();
// 1
// 2
// 3
throttle()
throttle
메서드는 지정된 초(seconds)만큼 대기 후 각 값을 반환하도록 컬렉션의 흐름을 제어합니다. 이 메서드는 특히 외부 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();