Коллекция - объект, который представляет собой массив каких-то данных с готовыми инструментами для поиска, фильтрации и различного рода манипуляций над этими данными с помощью вызова методов цепным способом.
По сути, это обычный массив [], который поставляется с готовыми инструментами для операций над этим массивом, что может в несколько раз уменьшить размер и упростить читаемость кода в местах, где идёт работа с массивами данных.
Коллекция является очень удобным инструментом, однако не каждый разработчик может с легкостью разобраться в его коде, если увидит его впервые. Я советую вам проверить на практике каждый метод, который будет рассмотрен на данной странице для более лучшего усвоения информации.
Создание коллекции
В Laravel, как правило, вы будете принимать готовую коллекцию (например, результат запроса в БД), а не создавать её.
Однако, создать коллекцию можно и самому, использовав функцию collect(). Можно вызывать эту функцию и без аргументов (тогда будет создана пустая коллекция), но также можно передать массив, который будет автоматически преобразован в коллекцию.
1 2 3 4 5 6 7 8 9 10 11// Создать пустую коллекцию $collection = collect(); // Создать коллекцию с данными $data = [ 'name' => 'Роман', 'city' => 'Москва', 'profession' => 'PHP разработчик', ]; $collection = collect($data);
Методы коллекции
Как я говорил ранее, коллекция - объект, в котором можно вызывать методы цепным способом. Это значит, что после каждого выполнения метода он вернет коллекцию.
Таким образом, можно выполнить несколько сложных (с точки зрения обычной работы с массивами) операций в рамках одного обращения к коллекции. Это очень удобно и упрощает читаемость кода.
all()
Возвращает все элементы коллекции в виде массива.
$collection = collect([1, 2, 3]);
// Получим значения в виде массива
$collection->all();
// [1, 2, 3]
toArray()
Возвращает все элементы коллекции в виде массива. Отличается от all() тем, что toArray() также преобразит в массив все вложенные объекты-коллекции (например Eloquent модели).
1 2 3 4 5 6 7 8 9 10 11 12 13$users = collect([ collect(['id' => 1, 'name' => 'Роман']), collect(['id' => 2, 'name' => 'Сергей']), ]); $users->toArray(); /* [ ['id' => 1, 'name' => 'Роман'], ['id' => 2, 'name' => 'Сергей'], ] */
Давайте на этом же примере, сравним этот метод с методом all()
1 2 3 4 5 6 7 8 9 10 11 12$users->all(); /* [ Collection { ['id' => 1, 'name' => 'Роман'] }, Collection { ['id' => 2, 'name' => 'Сергей'] }, ] */
avg(), average()
Возвращает среднее-арифметическое значение среди элементов коллекции. По факту, это один и тот же метод - average() является псевдонимом для метода avg().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24collect([1,3,8])->avg(); // 4 (потому что (1 + 3 + 8) / 3 = 4 /* * Еще один пример. */ $daysInMonthsCount = collect([ 'Январь' => 31, 'Февраль' => collect([28,29])->average(), // average() - то же, что и avg() 'Март' => 31, 'Апрель' => 30, 'Май' => 31, 'Июнь' => 30, 'Июль' => 31, 'Август' => 31, 'Сентябрь' => 30, 'Октябрь' => 31, 'Ноябрь' => 30, 'Декабрь' => 31, ]); $daysInMonthsCount->avg(); // Среднее количество дней в месяце - 30.458333333333
chunk()
Разбивает коллекцию на множество мелких коллекций определенной длины.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$collection = collect([1, 2, 3, 4, 5, 6, 7]); $chunks = $collection->chunk(4); $chunks->toArray(); /* [ [1, 2, 3, 4], [ 4 => 5, 5 => 6, 6 => 7, ] ] */
Как нам подсказывает документация Laravel, этот метод - хороший способ для вывода сетки в вашем отображении (view) в связке с каким-нибудь фронтенд фреймворком, например Bootstrap:
@foreach ($products->chunk(3) as $chunk)
<div class="row">
@foreach ($chunk as $product)
<div class="col-xs-4">{{ $product->name }}</div>
@endforeach
</div>
@endforeach
collapse()
Преобразует коллекцию массивов в единую коллекцию. Противоположность метода chunk().
$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]
combine()
Комбинирует ключи коллекции со значениями другого массива или коллекции.
$collection = collect(['name', 'surname']);
$combined = $collection->combine(['Роман', 'Сарваров']);
$combined->all();
// ['name' => 'Роман', 'surname' => 'Сарваров']
concat()
Добавляет вконец коллекции другую коллекцию или массив.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19$collected = collect(['Коллекция']) ->concat(['это']) ->concat(['очень']) ->concat(['просто']); /* * Также может принимать коллекцию: * * $collected = * collect(['Коллекция']) * ->concat(collect(['это'])) * ->concat(collect(['очень'])) * ->concat(collect(['просто'])); */ $collected->toArray(); // ['Коллекция', 'это', 'очень', 'просто']
contains(), some()
Проверяет коллекцию на наличие значения (аналог функции in_array для PHP массивов).
$collection = collect(['name' => 'Роман']);
$collection->contains('Roman'); // false
$collection->contains('роман'); // false
$collection->contains('Роман'); // true
Также с помощью этого метода можно удостовериться в существовании какой-то пары, передав значение во второй аргумент. Более того, между ними можно добавить оператор сравнения.
1 2 3 4 5 6 7 8 9 10 11 12$users = collect([ ['name' => 'Роман', 'age' => 23], ['name' => 'Денис', 'age' => 35], ['name' => 'Егор', 'age' => 14], ]); $users->contains('name', 'Максим'); // false $users->contains('name', 'Роман'); // true $users->contains('name', '!=', 'Максим'); // true $users->contains('age', '>', 30); // true $users->contains('age', '>=', 55); // false
Можно пойти дальше и в аргумент указать лишь callback-функцию, чтобы составлять свои условия. Продолжим предыдущий пример:
$users->contains(
fn($value, $key) => $value['age'] >= 35
); // true
$users->contains(
fn($value, $key) => $value['age'] > 55
); // false
Обратите внимание, что в этом методе используется нестрогое сравнение. Чтобы помимо значения сравнивался и тип данных, используйте метод containsStrict().
containsStrict()
По аналогии с contains() проверяет коллекцию на наличие какого-то значения, однако, по сравнению с ним, использует строгое сравнение (сравнивает еще и тип данных).
1 2 3 4 5 6 7 8 9 10 11$collection = collect([ ['name' => 'Роман', 'age' => 23], ['name' => 'Денис', 'age' => 35], ['name' => 'Егор', 'age' => 14], ]); $collection->contains('age', 23); // true $collection->contains('age', '23'); // true $collection->containsStrict('age', 23); // true $collection->containsStrict('age','23'); // false
count()
Возвращает количество элементов в массиве.
$collection = collect([1, 1, 5, 4]);
$collection->count(); // 4
countBy()
Подсчитывает число вхождений значений в коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18$collection = collect([ ['name' => 'Роман'], ['name' => 'Алексей'], ['name' => 'Сергей'], ['name' => 'Роман'], ]); $counted = $collection->countBy(); $counted->all(); /* [ 'Роман' => 2, 'Алексей' => 1, 'Сергей' => 1, ] */
Также, можно передать callback-функцию, если нужно реализовать свою логику подсчета:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21$collection = collect([ ['name' => 'Роман', 'contact_info' => '+7 (999) 888-33-44'], ['name' => 'Алексей', 'contact_info' => '+7 (495) 123-12-21'], ['name' => 'Сергей', 'contact_info' => 'some.email@sarvarov.dev'], ['name' => 'Роман', 'contact_info' => 'one.more@email.com'], ['name' => 'Андрей', 'contact_info' => '+7 (925) 454-89-17'], ]); // Посчитаем, сколько пользователей оставили свой Email в качестве контактной информации $countBy = $collection->countBy( fn($contactInfo) => strpos($contactInfo['contact_info'] ?? '', '@') !== false ? 'email' : 'phone' ); $countBy->all(); /* [ 'phone' => 3, 'email' => 2, ] */
crossJoin()
Возвращает все возможные перестановки коллекции с значениями переданного в аргументе массива. Простыми словами, возвращает значения "каждый с каждым".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28$workers = collect(['Роман', 'Сергей', 'Алексей']); $workersLife = $workers->crossJoin([ 'Встал с утра', 'Пошел на работу', 'Пришел с работы', 'Лёг спать' ]); $workersLife->all(); /* [ ['Роман', 'Встал с утра'], ['Роман', 'Пошел на работу'], ['Роман', 'Пришел с работы'], ['Роман', 'Лёг спать'], ['Сергей', 'Встал с утра'], ['Сергей', 'Пошел на работу'], ['Сергей', 'Пришел с работы'], ['Сергей', 'Лёг спать'], ['Алексей', 'Встал с утра'], ['Алексей', 'Пошел на работу'], ['Алексей', 'Пришел с работы'], ['Алексей', 'Лёг спать'], ] */
diff()
Сравнивает коллекцию с другой коллекцией или обычным массивом [] и возвращает разницу - те элементы, которые отсутствуют в передаваемом массиве.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$students = collect([ 'Евгений', 'Лена', 'Максим', 'Игорь', 'Аня', 'Петр', ]); // Проведем перекличку студентов и узнаем кто отсутствует на уроке $truants = $students->diff(['Игорь', 'Лена', 'Аня']); $truants->all(); // ['Евгений', 'Максим', 'Петр']
diffAssoc()
Сравнивает ключи и значения элементов одной коллекции с ключами и значениями элементов другой коллекцией или обычного массива [] и возвращает разницу - те элементы, которые отсутствуют в передаваемом массиве.
Отличается от diff() тем, что помимо значений сравнивает ещё и ключи.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$collection = collect([ 'name' => 'яблоко', 'color' => 'красный', 'type' => 'фрукт', ]); $diff = $collection->diffAssoc([ 'name' => 'яблоко', 'color' => 'зеленый', 'type' => 'фрукт', ]); $diff->all(); // ['color' => 'красный']
diffKeys()
Сравнивает ключи элементов одной коллекции с ключами элементов другой коллекцией или обычного массива [] и возвращает разницу - ключи, которые отсутствуют в передаваемом массиве, а также их значения.
1 2 3 4 5 6 7 8 9 10 11 12$collection = collect([ 'key_one' => 'Какое-то значение', 'key_two' => 'Этого элемента не будет в передаваемом массиве', ]); $diff = $collection->diffKeys([ 'key_one' => 'Ещё какое-то значение!!!', ]); $diff->all(); // ['key_two' => 'Этого элемента не будет в передаваемом массиве']
duplicates()
Возвращает повторяющиеся значения из коллекции. Используется нестрогое сравнение (не сравнивается тип, в отличие от duplicatesStrict()).
$collection = collect(['а', 'б', 'в', 'а', 'в']);
$dublicates = $collection->duplicates();
$dublicates->all()
// ['а', 'в']
Кроме того, можно в аргумент передать callback-функцию или же название ключа, по которому сравнивать элементы (в случае, если элементы коллекции - объекты/массивы).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$users = collect([ ['id' => 1, 'name' => 'Роман'], ['id' => 2, 'name' => 'Евгений'], ['id' => 3, 'name' => 'Максим'], ['id' => 4, 'name' => 'Роман'], ]); $dublicateNames = $users->duplicates(fn($val) => $val['name']); // Тоже самое, но проще: $dublicateNames = $users->duplicates('name'); $dublicateNames->all(); // ['Роман']
duplicatesStrict()
Возвращает повторяющиеся значения из коллекции. В отличие от duplicates() - помимо значения, сравнивает еще и тип данных.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19$collection = collect([ ['id' => 1], ['id' => '1'], ['id' => 'one'], ]); /* ПРОВЕРКА dublicates() */ $dublicates = $collection->duplicates('id'); $dublicates->all(); // ['1'] /* ПРОВЕРКА duplicatesStrict() */ $dublicates = $collection->duplicatesStrict('id'); $dublicates->all(); // [] - вернуло пустой массив, так как (int)1 !== (string)'1'
every()
Проверяет все элементы коллекции по какому-то условию. Если все элементы прошли тест - вернет true, в противном случае false.
Если коллекция пустая - будет возвращать true в любом случае.
В качестве аргумента передается callback-функция, которая должна содержать какой-то тест и возвращать true или false. В случае, если элементы коллекции - массив, можно передать ключ, оператор и значение.
1 2 3 4 5 6 7 8 9 10 11 12 13 14$users = collect([ ['id' => 1, 'name' => 'Роман', 'is_admin' => true], ['id' => 2, 'name' => 'Анна', 'is_admin' => true], ['id' => 3, 'name' => 'Борис', 'is_admin' => false], ]); /* Проверим, являются ли все пользователи в коллекции администраторами */ /* Эти 3 строки являются идентичными: */ // $users->every(fn($value, $key) => $value['is_admin'] ?? false); // $users->every('is_admin', '=', true); $users->every('is_admin', true); // false (Борис не администратор)
only()
Возвращает элементы коллекции с определенными ключами, которые были переданы в аргументе метода.
1 2 3 4 5 6 7 8 9 10 11$users = collect([ 'id' => 1, 'name' => 'Роман', 'password' => '$2y$10$nsipFleZ3hQkrmhW3N40aOFMqT.swZyyb/TgZ1JUu3H1QRMhxZ3Wq', 'email' => 'roman@sarvarov.dev', ]); $safeUsersDataCollection = $users->only('id', 'name'); $safeUsersDataCollection->all(); // ['id' => 1, 'name' => 'Роман']
Если нужно, наоборот, вернуть все элементы коллекции, кроме определенных - используйте except().
except()
Возвращает все элементы коллекции, за исключением тех, ключи которых переданы в функцию в виде массива. Противоположность метода only().
1 2 3 4 5 6 7 8 9 10 11$users = collect([ 'id' => 1, 'name' => 'Роман', 'password' => '$2y$10$nsipFleZ3hQkrmhW3N40aOFMqT.swZyyb/TgZ1JUu3H1QRMhxZ3Wq', 'email' => 'roman@sarvarov.dev', ]); $safeUsersDataCollection = $users->except('password', 'email'); $safeUsersDataCollection->all(); // ['id' => 1, 'name' => 'Роман']
unique(), uniqueStrict()
Возвращает уникальные значения элементов коллекции. Сохраняет ключи (если нужно их сбросить - примените к коллекции метод values()).
uniqueStrict() отличается от unique() тем, что производит строгое сравнение (помимо значения, сравнивает ещё и тип данных, а не делает приведение).
$collection = collect([1, 1, '1', 2, 'строка', 2, null, 4, 2, []]);
/* Нестрогое сравнение данных */
$collection->unique()->values()->all();
// [1, 2, 'строка', null, 4]
/* Строгое сравнение данных */
$collection->uniqueStrict()->values()->all();
// [1, '1', 2, 'строка', null, 4, []]
Можно передать строку с ключом, тогда будут возвращены все элементы с уникальными значениями по этому ключу.
Кроме того, можно передать callback-функцию со своей логикой определения уникальности элемента.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27$gadgets = collect([ ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'телефон'], ['name' => 'iPhone 5', 'brand' => 'Apple', 'type' => 'телефон'], ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'часы'], ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'телефон'], ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'часы'], ]); $gadgets->unique('brand')->values()->all(); /* [ ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'телефон'], ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'телефон'], ] */ $gadgets->unique( fn($item, $key) => "{$item['brand']}_{$item['type']}" )->values()->all(); /* [ ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'телефон'], ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'часы'], ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'телефон'], ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'часы'], ] */
filter()
Фильтрует и возвращает только те элементы коллекции, которые соответствуют заданному условию. Противоположность метода reject().
Условие определяется в переданной в аргументе callback-функцией. Если эта функция возвращает true - элемент остается в выборке, если false - то нет.
Если передать callback-функцию в виде аргумента, то из выборки пропадут все элементы, эквивалентные false.
1 2 3 4 5 6 7 8 9 10 11 12 13 14$collection = collect([0, null, 1, 2, 3, 4, '', 5, 6, 7, 8, false, []]); // Оставим только цифры, которые делятся на 2. Так же оставим все нечисловые значения для будущего теста. $filtered = $collection->filter( fn($value, $key) => (is_numeric($value) && $value % 2 === 0) || !is_numeric($value) ); $filtered->all(); // 0, null, 2, 4, '', 6, 8, false, [] $filtered = $filtered->filter(); $filtered->all(); // [2, 4, 6, 8]
reject()
Фильтрует и возвращает элементы коллекции с помощью callback-функции. Является противоположностью метода filter(): если callback-функция возвращает true - этот элемент НЕ попадет в финальную выборку.
1 2 3 4 5 6 7 8 9 10 11$collection = collect([0, null, 1, 2, 3, 4, '', 5, 6, 7, 8, false, []]); /* Удалим все элементы коллекции, которые являются true */ $rejected = $collection->reject(); $rejected->all(); // [0, null, '', false, []] /* Удалим все нечисловые значения */ $rejected = $rejected->reject(fn($value, $key) => !is_numeric($value)); $rejected->all(); // [0]
get()
Возвращает элемент коллекции по переданному ключу. Если такого ключа не существует, вернет null или значение по умолчанию (которое можно передать во втором аргументе).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$user = collect([ 'id' => 1, 'name' => 'Роман', ]); $user->get('name'); // Роман $user->get('is_admin', false); /* * Вернет false (т.к. ключа is_admin не существует) * * Тоже самое что $user['is_admin'] ?? false * и $user->get('is_admin', fn() => false) */
pluck()
Извлекает все значения элементов по заданному ключу. Можно указать ещё одно название ключа (во втором аргументе), в таком случае ключи в новой коллекции будут установлены на значения ключей исходной коллекции, а также значения могут быть перезаписаны при дублировании.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$users = collect([ ['id' => 34, 'name' => 'Роман'], ['id' => 875, 'name' => 'Евгений'], ['id' => 166, 'name' => 'Максим'], ['id' => 819, 'name' => 'Роман'], ['id' => 34, 'name' => 'Петр'], ]); $usersNames = $users->pluck('name'); $usersNames->all(); // ['Роман', 'Евгений', 'Максим', 'Роман']; $users = $users->pluck('name', 'id'); $users->all(); // [34 => 'Петр', 875 => 'Евгений', 166 => 'Максим', 819 => 'Роман'];
search()
Выполняет поиск по значениям элементов коллекции и возвращает ключ элемента, если значение было найдено, и false если значение не получилось найти. Поиск происходит до первого найденного элемента.
В процессе поиска идёт нестрогое сравнение (не сопоставляются типы данных переменных). Чтобы использовать строгое сравнение - передайте true во второй аргумент при вызове метода.
Кроме того, вместо строки с искомым значением, можно передать callback-функцию со своей логикой нахождения нужного элемента.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23$collection = collect([2, 6, 4, 4, '6', 8]); $collection->search(4); // 2 (находит только первое значение и прекращает поиск) $collection->search('6', true); // 4 (строгое сравнение типов) $collection->search(9999); // false $users = collect([ ['id' => 1, 'name' => 'Илья', 'age' => 35], ['id' => 2, 'name' => 'Роман', 'age' => 23], ['id' => 3, 'name' => 'Глеб', 'age' => 84], ['id' => 4, 'name' => 'Максим', 'age' => 14], ]); /* Найдем Романа */ $users->search(fn($value, $key) => Str::startsWith( Str::lower($value['name']), 'рома') ); // 1
where(), whereStrict()
Фильтрует коллекцию с помощью переданной пары ключей/значений. В первый аргумент передается ключ, во второй - значение. Также, между ними можно добавить ещё один аргумент - оператор.
whereStrict() отличается от where() тем, что производит строгое сравнение (помимо значения, сравнивает ещё и тип данных, а не делает приведение).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41$users = collect([ ['id' => 1, 'name' => 'Илья', 'age' => 28], ['id' => 2, 'name' => 'Роман', 'age' => 23, 'is_admin' => true], ['id' => 3, 'name' => 'Максим', 'age' => 44], ['id' => 4, 'name' => 'Семён', 'age' => 29], ['id' => 5, 'name' => 'Василий', 'age' => 32, 'is_admin' => true], ['id' => 6, 'name' => 'Владимир', 'age' => 16], ['id' => 7, 'name' => 'Роман', 'age' => 58], ['id' => 8, 'name' => 'Максим', 'age' => 23], ]); /* Простой поиск */ $admins = $users->where('is_admin', true); // Тоже самое что и $users->where('is_admin', 1); // Тоже самое что и $users->where('is_admin', '=', true); $admins->all(); /* [ ['id' => 2, 'name' => 'Роман', 'age' => 23, 'is_admin' => true], ['id' => 5, 'name' => 'Василий', 'age' => 32, 'is_admin' => true], ] */ /* Строгое сравнение данных */ $admins = $users->whereStrict('is_admin', 1); $admins->all(); // [] - ничего не нашло, так как (int)1 !== (bool)true /* Поиск с оператором */ $oldGuys = $users->where('age', '>', 30); $oldGuys->all(); /* [ ['id' => 3, 'name' => 'Максим', 'age' => 44], ['id' => 5, 'name' => 'Василий', 'age' => 32, 'is_admin' => true], ['id' => 7, 'name' => 'Роман', 'age' => 58], ] */
whereBetween()
Фильтрует элементы коллекции по диапазону переданного значения. Противоположность метода whereNotBetween().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18$users = collect([ ['id' => 1, 'name' => 'Илья', 'age' => 8], ['id' => 2, 'name' => 'Роман', 'age' => 22], ['id' => 3, 'name' => 'Максим', 'age' => 6], ['id' => 4, 'name' => 'Семён', 'age' => 17], ['id' => 5, 'name' => 'Василий', 'age' => 24], ]); /* Найдем пользователей, которым от 1 до 10 лет */ $youngGuys = $users->whereBetween('age', [1, 10]); $youngGuys->all(); /* [ ['id' => 1, 'name' => 'Илья', 'age' => 8], ['id' => 3, 'name' => 'Максим', 'age' => 6], ] */
whereNotBetween()
Фильтрует (удаляет) элементы коллекции по диапазону переданного значения. Противоположность метода whereBetween().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$collection = collect([ ['product' => 'Стол', 'price' => 5000], ['product' => 'Стул', 'price' => 3500], ['product' => 'Шкаф', 'price' => 12000], ['product' => 'Тумбочка', 'price' => 3700], ['product' => 'Кровать', 'price' => 9500], ]); $collection->whereNotBetween('price', [3000, 4000])->all(); /* [ ['product' => 'Стол', 'price' => 5000], ['product' => 'Шкаф', 'price' => 12000], ['product' => 'Кровать', 'price' => 9500], ] */
whereIn(), whereInStrict()
Фильтрует элементы коллекции по ключу/значению, содержащимся в переданном массиве.
whereInStrict() отличается от whereIn() тем, что производит строгое сравнение (помимо значения, сравнивает ещё и тип данных, а не делает приведение).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26$articles = collect([ ['id' => 1, 'title' => 'Первая статья', 'category' => 117], ['id' => 2, 'title' => 'Вторая статья', 'category' => 56], ['id' => 3, 'title' => 'Третья статья', 'category' => 98], ['id' => 4, 'title' => 'Четвертая статья', 'category' => '117'], ['id' => 5, 'title' => 'Пятая статья', 'category' => 1], ]); /* Нестрогое сравнение */ $articles->whereIn('category', [98, 117])->all(); /* [ ['id' => 1, 'title' => 'Первая статья', 'category' => 117], ['id' => 3, 'title' => 'Третья статья', 'category' => 98], ['id' => 4, 'title' => 'Четвертая статья', 'category' => '117'], ] */ /* Строгое сравнение */ $articles->whereInStrict('category', [98, 117])->all(); /* [ ['id' => 1, 'title' => 'Первая статья', 'category' => 117], ['id' => 3, 'title' => 'Третья статья', 'category' => 98], ] */
whereNotIn(), whereNotInStrict()
Фильтрует (удаляет) элементы коллекции по ключу/значению, содержащимся в переданном массиве.
whereNotInStrict() отличается от whereNotIn() тем, что производит строгое сравнение (помимо значения, сравнивает ещё и тип данных, а не делает приведение).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26$articles = collect([ ['id' => 1, 'title' => 'Первая статья', 'category' => 117], ['id' => 2, 'title' => 'Вторая статья', 'category' => 56], ['id' => 3, 'title' => 'Третья статья', 'category' => 98], ['id' => 4, 'title' => 'Четвертая статья', 'category' => '117'], ['id' => 5, 'title' => 'Пятая статья', 'category' => 1], ]); /* Нестрогое сравнение */ $articles->whereNotIn('category', [98, 117])->all(); /* [ ['id' => 2, 'title' => 'Вторая статья', 'category' => 56], ['id' => 5, 'title' => 'Пятая статья', 'category' => 1], ] */ /* Строгое сравнение */ $articles->whereNotInStrict('category', [98, 117])->all(); /* [ ['id' => 2, 'title' => 'Вторая статья', 'category' => 56], ['id' => 4, 'title' => 'Четвертая статья', 'category' => '117'], ['id' => 5, 'title' => 'Пятая статья', 'category' => 1], ] */
whereInstanceOf()
Фильтрует элементы коллекции по переданному типу класса.
$collection = collect([
new User(),
new Post(),
new Admin(), // extends User
new User(),
new Task(),
]);
$collection->whereInstanceOf(User::class)->all();
// [App\User, App\Admin, App\User]
whereNotNull()
Возвращает все элементы коллекции, где значение не является null. Может работать как с простыми коллекциями, так и многомерными (но в таком случае нужно передать ключ в качестве аргумента). Противоположность метода whereNull().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22$collection = collect([0, null, '', [], false]); $collection->whereNotNull()->all(); // [0, null, '', [], false] $collection = collect([ ['id' => 1, 'value' => 0], ['id' => 2, 'value' => null], ['id' => 3, 'value' => ''], ['id' => 4, 'value' => []], ['id' => 5, 'value' => false], ]); $collection->whereNotNull('value')->all(); /* [ ['id' => 1, 'value' => 0], ['id' => 3, 'value' => ''], ['id' => 4, 'value' => []], ['id' => 5, 'value' => false], ] */
whereNull()
Возвращает все элементы коллекции, где значение является null. Может работать как с простыми коллекциями, так и многомерными (но в таком случае нужно передать ключ в качестве аргумента). Противоположность метода whereNotNull().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21$collection = collect([0, null, '', [], false, null]); $collection->whereNull()->all(); // [1 => null, 5 => null] $collection = collect([ ['id' => 1, 'value' => 0], ['id' => 2, 'value' => null], ['id' => 3, 'value' => ''], ['id' => 4, 'value' => []], ['id' => 5, 'value' => false], ['id' => 6, 'value' => null], ]); $collection->whereNull('value')->all(); /* [ ['id' => 2, 'value' => null], ['id' => 6, 'value' => null], ] */
first()
Возвращает первый элемент коллекции. Если передать первым аргументом callback-функцию, то будет возвращен первый элемент, который удовлетворяет этому условию.
В качестве второго аргумента можно установить значение по умолчанию, которое будет возвращено, если не найден ни один подходящий элемент коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14$collection->first(); // 1 /* Вернем первое число, которое делится на 2 без остатка (но не самое 2) */ $collection->first( fn ($value, $key) => $value !== 2 && $value % 2 === 0 ); // 4 /* Попросим несуществующее значение. Должно вернуть значение по умолчанию */ $collection->first( fn ($value) => $value === 1111, 'default' ); // default
firstWhere()
Возвращает первый элемент коллекции с заданным ключом и значением. Также можно использовать оператор сравнения, если передать его в качестве аргумента.
Если передать только ключ (без значения), то будет возвращен первый элемент где такой ключ существует и его значение является истинным.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$users = collect([ ['name' => 'Илья', 'age' => null], ['name' => 'Роман', 'age' => 23], ['name' => 'Глеб', 'age' => 84], ['name' => 'Максим', 'age' => 14], ]); $users->firstWhere('name', 'Максим'); // ['name' => 'Максим', 'age' => 14] $users->firstWhere('age', '>', '25'); // ['name' => 'Глеб', 'age' => 84] $users->firstWhere('age'); // ['name' => 'Роман', 'age' => 23]
shift()
Удаляет и возвращает первый элемент коллекции.
$collection = collect([1, 2, 3, 4, 5]);
$collection->shift();
// 1
$collection->all();
// [2, 3, 4, 5]
last()
Возвращает последний элемент коллекции. Если передать первым аргументом callback-функцию, то будет возвращен последний элемент, который удовлетворяет этому условию.
В качестве второго аргумента можно установить значение по умолчанию, которое будет возвращено, если не найден ни один подходящий элемент коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]); $collection->last(); // 9 /* Вернем первое число, которое делится на 2 без остатка */ $collection->last( fn ($value, $key) => $value % 2 === 0 ); // 8 /* Попросим несуществующее значение. Должно вернуть значение по умолчанию */ $collection->last( fn ($value) => $value === 1111, 'default' ); // default
pop()
Удаляет и возвращает последний элемент коллекции.
$collection = collect([1, 2, 3, 4, 5]);
$collection->pop();
// 5
$collection->all();
// [1, 2, 3, 4]
prepend()
Добавляет элемент в начало коллекции. В качестве второго аргумента можно передать строку с ключом, который будет установлен этому элементу.
$collection = collect([1, 2, 3, 4, 5]);
$collection->prepend(0);
$collection->all();
// [0, 1, 2, 3, 4, 5]
$collection = collect(['один' => 1, 'два' => 2]);
$collection->prepend(0, 'ноль');
$collection->all();
// ['ноль' => 0, 'один' => 1, 'два' => 2]
push()
Добавляет элемент коллекции в конец коллекции.
$collection = collect([1, 2, 3, 4]);
$collection->push(5);
$collection->all();
// [1, 2, 3, 4, 5]
pull()
Удаляет и возвращает элемент коллекции по переданному ключу.
$table = collect(['id' => 512, 'name' => 'Стол', 'price' => 5000]);
$table->pull('id');
// 512
$table->all();
// ['name' => 'Стол', 'price' => 5000]
put()
Устанавливает значение по переданному ключу. Если такого ключа не существует - добавляет новый элемент в конец коллекции.
1 2 3 4 5 6 7 8$table = collect(['id' => 512, 'name' => 'Стол', 'price' => 5000]); $table ->put('price', 7500) ->put('description', 'Он стоит!'); $table->all(); // ['id' => 512, 'name' => 'Стол', 'price' => 7500, 'description' => 'Он стоит!']
random()
Возвращает случайный элемент(ы) коллекции.
$collection = collect([1, 2, 3, 4, 5]);
$collection->random();
// 4 (выводит случайным образом)
$collection->random(2);
// [1, 3] (выводит случайным образом)
shuffle()
Случайным образом перемешивает элементы коллекции. В качестве аргумента можно передать seed (параметр переинициализации).
$collection = collect([1, 2, 3, 4, 5]);
$collection->shuffle();
// [4, 3, 1, 5, 2] (мешается случайным образом)
$collection->shuffle(1111);
// [5, 2, 3, 4, 1] (всегда в таком порядке при seed 1111)
each()
Делает перебор элементов коллекции на основе callback-функции. Аналог стандартного PHP оператора foreach() для коллекций.
Аргумент этого метода принимает callback-функцию, которая в свою очередь принимает два аргумента - значение и ключ.
Если необходимо прекратить цикл - нужно использовать return false, если необходимо пропустить какой-то элемент - нужно возвращать пустоту, используя return.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37$collection = collect(['Ноль', 'Один', 'Два', 'Три', 'Четыре', 'Пять', 'Шесть']); /* * Выведем на экран все цифры без, которые делятся на 2 и не больше 4 */ $collection->each(function ($value, $key) { if ($key > 4) { return false; // Ключ элемента больше чем 4, завершим цикл } if ($key === 0 || $key % 2 !== 0) { return; // Не делится на 2 без остатка, перейдем к следующему элементу коллекции } echo $value . PHP_EOL; }); /* * Два * Четыре */ /* * Это тоже самое, что: * * foreach ($collection->toArray() as $key => $value) { * if ($key > 4) { * break; * } * * if ($key === 0 || $key % 2 !== 0) { * continue; * } * * echo $value . PHP_EOL; * } */
eachSpread()
Делает перебор элементов коллекции, передавая каждое значение вложенного элемента в callback-функцию.
В отличие от each(), позволяет делать перебор коллекций, элементы которых состоят из массивов, более читабельным (за счёт обращения к именованным аргументам, а не к $value).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30$users = collect([ ['Егор', 11, 'Тюмень'], // Можно использовать и массив ['Роман', 23, 'Москва'], collect(['Денис', 16, 'Берлин']), // ... и коллекции ]); $users->eachSpread(function ($name, $age, $city) { if ($age >= 18) { return; } echo "Пользователю $name из г. $city менее 18-ти лет!\n"; }); /* * Пользователю Егор из г. Тюмень менее 18-ти лет! * Пользователю Денис из г. Берлин менее 18-ти лет! */ /* * Если делать с помощью обычного each() - будет менее читабельно: * * $users->each(function ($value, $key) { * if ($value[1] >= 18) { * return; * } * * echo "Пользователю {$value[0]} из г. {$value[2]} менее 18-ти лет!\n"; * }); */
Как и в each(), можно использовать return (для перехода к следующему элементу) и return false (для прекращения цикла).
reduce()
Перебирает каждый элемент коллекции и передает полученный в конкретном цикле результат к следующей итерации.
1 2 3 4 5 6 7 8 9 10 11 12 13 14$users = collect([ ['id' => 1, 'name' => 'Роман', 'balance' => 350, 'is_admin' => true], ['id' => 2, 'name' => 'Елизавета', 'balance' => 1200], ['id' => 3, 'name' => 'Максим', 'balance' => 540], ['id' => 4, 'name' => 'Егор', 'balance' => 3720], ]); /* Посчитаем баланс всех пользователей, исключая администраторов */ $totalUserBalance = $users->reduce(function ($carry, $value) { return $carry + (empty($value['is_admin']) ? $value['balance'] : 0); }); echo $totalUserBalance; // 5460
Начальное значение $carry - всегда null. Если нужно это изменить - передайте новое значение во второй аргумент при вызове метода.
map()
Перебирает каждый элемент коллекции и передаёт его в callback-функцию, которая, в свою очередь, может вернуть измененное значение, формируя тем самым новую - "измененную" коллекцию.
1 2 3 4 5 6 7 8 9 10 11 12$notTrimmedStr = collect([ ' тест ', 'trimmed_already', '/ ещё один тест ', ]); $trimmedStr = $notTrimmedStr->map( fn($value, $key) => (string)Str::of($value)->trim('/ ') ); $trimmedStr->all(); // ['тест', 'trimmed_already', 'ещё один тест']
transform()
Массово изменяет элементы коллекции через callback-функцию. По сути, это тоже самое, что и map(), за единственным исключением: он изменяет вызываемую коллекцию, а не создает новый экземпляр класса.
$collection = collect([1, 2, 3]);
$collection->transform(fn($value, $key) => /* ... */ $value);
// Тоже самое что и:
$collection = $collection->map(fn($value, $key) => /* ... */ $value);
mapInto()
Делает перебор элементов коллекции и создает новый экземпляр переданного в метод класса, передав в его конструктор значение коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35class User { /** @var string */ private $name; /** * User constructor. * * @param string $name */ public function __construct(string $name) { $this->name = $name; } } // Клиентский код $userNames = collect(['Роман', 'Виталий', 'Егор']); $users = $userNames->mapInto(User::class); $users->all(); /* [ User { name: 'Роман' }, User { name: 'Виталий' }, User { name: 'Егор' }, ] */
mapSpread()
Делает перебор элементов коллекции, передавая каждое значение вложенного элемента в callback-функцию, которая, в свою очередь, может вернуть измененное значение, формируя тем самым новую - "измененную" коллекцию.
В отличие от map(), позволяет делать перебор коллекций, элементы которых состоят из массивов, более читабельным (за счёт обращения к именованным аргументам, а не к $value).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24$users = collect([ [1, 'роман'], [2, 'егор'], [3, 'александр'] ]); // Сделаем так, чтобы имена были с заглавной буквы $users = $users->mapSpread(fn($id, $name) => [$id, Str::ucfirst($name)]); $users->all(); /* * [ * [1, 'Роман'], * [2, 'Егор'], * [3, 'Александр'], * ] */ /* * Можно было это сделать и с помощью map(), но выглядит это не очень красиво: * * $users = $users->map(fn($values) => [$values[0], Str::ucfirst($values[1])]); */
mapToGroups()
Перебирает все элементы коллекции и группирует их используя callback-функцию.
Callback-функция должна вернуть ассоциативный массив, содержащий одну пару ключ =>
значение, таким образом формируя новый набор сгруппированных значений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22$users = collect([ ['id' => 1, 'name' => 'Роман', 'country' => 'Россия', 'city' => 'Москва'], ['id' => 2, 'name' => 'Том', 'country' => 'США', 'city' => 'Нью-Йорк'], ['id' => 3, 'name' => 'Глеб', 'country' => 'Россия', 'city' => 'Санкт-Петербург'], ['id' => 4, 'name' => 'Джордж', 'country' => 'США', 'city' => 'Вашингтон'], ['id' => 5, 'name' => 'Алексей', 'country' => 'Россия', 'city' => 'Уфа'], ['id' => 6, 'name' => 'Патрик', 'country' => 'Австралия', 'city' => 'Сидней'], ]); $usersLocations = $users->mapToGroups( fn($value, $key) => [$value['country'] => $value['city']] ); $usersLocations->toArray(); /* [ 'Россия' => ['Москва', 'Санкт-Петербург', 'Уфа'], 'США' => ['Нью-Йорк','Вашингтон'], 'Австралия' => ['Сидней'], ] */
mapWithKeys()
Перебирает все элементы коллекции через callback-функцию и создаёт новую коллекцию. Отличается от mapToGroup() тем, что не создаёт массив с повторяющиеся значениями, а перезаписывает их, если ключ уже существует.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17$collection = collect([ ['name' => 'Сергей', 'email' => 'sergey@test.com'], ['name' => 'Роман', 'email' => 'roma1991@mail.ru'], ['name' => 'Роман', 'email' => 'roman@sarvarov.dev'], ]); $keyed = $collection->mapWithKeys( fn($item) => [$item['name'] => $item['email']] ); $keyed->all(); /* [ 'Сергей' => 'sergey@test.com', 'Роман' => 'roman@sarvarov.dev', ] */
flatten()
Преобразует многомерную коллекцию (коллекцию с несколькими уровнями) в одномерную.
1 2 3 4 5 6 7 8 9$collection = collect([ 'name' => 'Роман', 'languages' => ['php', 'sql', 'javascript', 'css', 'html'], ]); $flattened = $collection->flatten(); $flattened->all(); // ['Роман', 'php', 'sql', 'javascript', 'css', 'html']
Можно передать глубину уровней в качестве аргумента:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$collection = collect([ 'уровень 1' => [ 'уровень 2' => [ 'уровень 3', ], ], ]); $flattened = $collection->flatten(1); $flattened->all(); /* [ ['уровень 3'], ] */
flatMap()
Также как и map(), перебирает каждый элемент коллекции и передаёт его в callback-функцию, которая, в свою очередь, может вернуть измененное значение, формируя тем самым новую - "измененную" коллекцию. После этого сглаживает коллекцию на 1 уровень.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20$collection = collect([ ['name' => 'Роман'], ['age' => 23], ['country' => 'Россия'], ['city' => 'Москва'], ]); $flattened = $collection->flatMap( fn($values) => array_map('mb_strtoupper', $values) ); $flattened->all(); /* [ 'name' => 'РОМАН', 'age' => '23', 'country' => 'РОССИЯ', 'city' => 'МОСКВА', ] */
flip()
Меняет местами ключи и их значения.
1 2 3 4 5 6 7 8 9 10 11 12 13 14$collection = collect([ 'ключ' => 'значение', 'было ключом' => 'стало значением', ]); $flipped = $collection->flip(); $flipped->all(); /* [ 'значение' => 'ключ', 'стало значением' => 'было ключом', ] */
forget()
Удаляет элемент коллекции по его ключу. Также можно передать массив ключей, которые нужно удалить. Аналог PHP функции unset.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20$roman = collect([ 'name' => 'Роман', 'age' => 23, 'city' => 'Москва', 'password' => '$2y$10$nsipFleZ3hQkrmhW3N40aOFMqT.swZyyb/TgZ1JUu3H1QRMhxZ3Wq', 'email' => 'roman@sarvarov.dev', 'phone' => '+7 (999) 123-45-67', ]); // Можно удалить единственный ключ $roman->forget('password'); // Можно удалить несколько ключей сразу $roman->forget(['phone', 'email']); // Можно использовать PHP функцию unset() unset($roman['city']); $roman->all(); // ['name' => 'Роман', 'age' => 23]
forPage()
Позволяет разбить коллекцию на страницы и возвращает какую-то из них. В аргументе нужно передать номер страницы и кол-во элементов на одной странице.
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]);
// Возьмём 3 элементы с начала второй страницы:
$chunk = $collection->forPage(2, 3);
$chunk->all();
// [4, 5, 6]
groupBy()
Группирует элементы коллекции по переданному ключу.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25$users = collect([ ['name' => 'Роман', 'city' => 'Москва'], ['name' => 'Том', 'city' => 'Нью-Йорк'], ['name' => 'Глеб', 'city' => 'Москва'], ['name' => 'Патрик', 'city' => 'Сидней'], ]); // Разделим коллекцию на группы по городам $usersCities = $users->groupBy('city'); $usersCities->toArray(); /* [ 'Москва' => [ ['name' => 'Роман', 'city' => 'Москва'], ['name' => 'Глеб', 'city' => 'Москва'] ], 'Нью-Йорк' => [ ['name' => 'Том', 'city' => 'Нью-Йорк'], ], 'Сидней' => [ ['name' => 'Патрик', 'city' => 'Сидней'], ], ] */
Можно передать несколько ключей в виде массива для многоуровневой группировки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40$users = collect([ ['name' => 'Роман', 'country' => 'Россия', 'city' => 'Москва'], ['name' => 'Олег', 'country' => 'Украина', 'city' => 'Одесса'], ['name' => 'Евгений', 'country' => 'Россия', 'city' => 'Липецк'], ['name' => 'Антонина', 'country' => 'Беларусь', 'city' => 'Гомель'], ['name' => 'Герман', 'country' => 'Украина', 'city' => 'Одесса'], ['name' => 'Анатолий', 'country' => 'Казахстан', 'city' => 'Караганда'], ]); $usersByLocations = $users->groupBy(['country', 'city']); $usersByLocations->toArray(); /* [ 'Россия' => [ 'Москва' => [ ['name' => 'Роман', 'country' => 'Россия', 'city' => 'Москва'], ], 'Липецк' => [ ['name' => 'Евгений', 'country' => 'Россия', 'city' => 'Липецк'], ], ], 'Украина' => [ 'Одесса' => [ ['name' => 'Олег', 'country' => 'Украина', 'city' => 'Одесса'], ['name' => 'Герман', 'country' => 'Украина', 'city' => 'Одесса'], ], ] 'Беларусь' => [ 'Гомель' => [ ['name' => 'Антонина', 'country' => 'Беларусь', 'city' => 'Гомель'], ], ], 'Казахстан' => [ 'Караганда' => [ ['name' => 'Анатолий', 'country' => 'Казахстан', 'city' => 'Караганда'], ], ], ] */
Вместо ключа, в качестве аргумента можно передать callback-функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33// Допустим, есть работники, с которыми можно связаться по одному номеру телефона $workers = collect([ ['name' => 'Роман', 'phone_number' => '+7 495 123-33-44'], ['name' => 'Ольга', 'phone_number' => '84951233344'], ['name' => 'Петр', 'phone_number' => '8 (499) 987-65-43'], ['name' => 'Анна', 'phone_number' => '+7 499 987-65-43'], ]); // Как мы видим, они в разном формате. Давайте сгруппируем их, используя callback-функцию $phoneNumbers = $workers->groupBy(function ($value, $key) { $phoneNumber = Str::of(preg_replace('/\D/', '', $value['phone_number'])); // Если номер телефона начинается на 7, заменим на 8 if ($phoneNumber->startsWith('7')) { $phoneNumber = $phoneNumber->replaceFirst('7', '8'); } return (string) $phoneNumber; }); $phoneNumbers->toArray(); /* [ '84951233344' => [ ['name' => 'Роман', 'phone_number' => '+7 495 123-33-44'], ['name' => 'Ольга', 'phone_number' => '84951233344'], ], '84999876543' => [ ['name' => 'Петр', 'phone_number' => '8 (499) 987-65-43'], ['name' => 'Анна''phone_number' => '+7 499 987-65-43'], ], ] */
Если вам нужно сохранить ключи элементов, то необходимо передать true в качестве второго аргумента. Если не передать - ключи будут потеряны во время группировки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41$users = collect([ 'user_564' => ['name' => 'Роман', 'city' => 'Москва'], 'user_110' => ['name' => 'Вацлав', 'city' => 'Варшава'], 'user_1097' => ['name' => 'Петр', 'city' => 'Минск'], 'user_849' => ['name' => 'Вениамин', 'city' => 'Москва'], ]); $usersByLocations = $users->groupBy('city', true); $usersByLocations->toArray(); /* [ 'Москва' => [ 'user_564' => ['name' => 'Роман', 'city' => 'Москва'], 'user_849' => ['name' => 'Вениамин', 'city' => 'Москва'], ], 'Варшава' => [ 'user_110' => ['name' => 'Вацлав', 'city' => 'Варшава'], ], 'Минск' => [ 'user_1097' => ['name' => 'Петр', 'city' => 'Минск'], ], ] */ /* * Если не установить в preserveKeys true, то вернулось бы так: * [ * 'Москва' => [ * ['name' => 'Роман', 'city' => 'Москва'], * ['name' => 'Вениамин', 'city' => 'Москва'], * ], * 'Варшава' => [ * ['name' => 'Вацлав', 'city' => 'Варшава'], * ], * 'Минск' => [ * ['name' => 'Петр', 'city' => 'Минск'], * ], * ] */
has()
Проверяет существование ключа в коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18$collection = collect(['account_id' => 1, 'product' => 'Стол', 'amount' => 5]); $collection->has('product'); // true $collection->has(['product', 'amount']); // true $collection->has(['amount', 'price']); // false /* * Будет тот же результат, если использовать стандартные средства PHP: * * isset($collection['product']) // true * isset($collection['product'], $collection['amount']) // true * isset($collection['amount'], $collection['price']) // false */
intersect()
Удаляет все значения коллекции, которые отсутствуют в переданном массиве. Можно передать не массив, а строку с одним значением.
$collection = collect(['Стул', 'Стол', 'Шкаф']);
$intersect = $collection->intersect(['Стул', 'Шкаф', 'Подоконник']);
$intersect->all();
// ['Стул', 'Шкаф']
intersectByKeys()
Удаляет все ключи коллекции, которые отсутствуют в переданном массиве. Как и в intersect() - можно передать не массив, а строку с одним значением.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$users = collect([ ['id' => 1, 'name' => 'Роман', 'is_admin' => true], ['id' => 2, 'name' => 'Елизавета'], ['id' => 3, 'name' => 'Максим'], ]); $admins = $users->intersectByKeys('is_admin'); // Можно передать и несколько значений в виде массива: ['is_admin', 'name'] и т.д. $admins->all(); /* [ ['id' => 1, 'name' => 'Роман', 'is_admin' => true] ] */
isEmpty()
Проверяет, пустая ли коллекция и возвращает true (если пустая) или false (если в ней есть хотя бы один элемент). Противоположность метода isNotEmpty().
collect([])->isEmpty();
// true
collect([1, 2, 3])->isEmpty();
// false
isNotEmpty()
Проверяет, пустая ли коллекция и возвращает true, если в ней есть хотя бы один элемент, или false, если она пустая. Противоположность метода isEmpty().
collect([])->isNotEmpty();
// false
collect([1, 2, 3])->isNotEmpty();
// true
implode()
Возвращает строку с чередованием элементов коллекции через переданный в аргумент функции разделитель. Работает по аналогии стандартной в PHP функции implode().
Если коллекция многомерная, то первым аргументом указывается ключ, значения которого нужно чередовать.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15/* Простая коллекция */ $friends = collect(['Рома', 'Миша', 'Петя'])->implode(', '); echo "Пошли как-то $friends в бар..."; // Пошли как-то Рома, Миша, Петя в бар... /* Многомерная коллекция */ $friends = collect([ ['id' => 1, 'name' => 'Рома', 'city' => 'Москва'], ['id' => 2, 'name' => 'Миша', 'city' => 'Москва'], ['id' => 3, 'name' => 'Петя', 'city' => 'Москва'], ])->implode('name', ', '); echo "Пошли как-то $friends в бар..."; // Пошли как-то Рома, Миша, Петя в бар...
join()
Возвращает строку с чередованием элементов коллекции через переданный в аргумент функции разделитель. Отличается от метода implode() тем, что работать может только с одномерными коллекциями (не умеет чередовать по ключам), а также может принимать второй аргумент - последний разделитель.
collect(['а', 'б', 'в'])->join(', '); // а, б, в
collect(['а', 'б', 'в'])->join(', ', ' и '); // а, б и в
collect(['а', 'б'])->join(', ', ' и '); // а и б
collect(['а'])->join(', ', ' и '); // а
keyBy()
Устанавливает ключ к элементам коллекции, беря за основу значение переданного ключа.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$users = collect([ ['id' => 113, 'name' => 'Роман'], ['id' => 567, 'name' => 'Борис'], ['id' => 392, 'name' => 'Артур'], ]); $keyed = $users->keyBy('id'); $keyed->all(); /* [ 113 => ['id' => 113, 'name' => 'Роман'], 567 => ['id' => 567, 'name' => 'Борис'], 392 => ['id' => 392, 'name' => 'Артур'], ] */
Как и во многих других методах коллекции, вместо названия ключа можно передать callback-функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$users = collect([ ['id' => 113, 'name' => 'Роман'], ['id' => 567, 'name' => 'Борис'], ['id' => 392, 'name' => 'Артур'], ]); $keyed = $users->keyBy(fn($value) => "user_{$value['id']}"); $keyed->all(); /* [ 'user_113' => ['id' => 113, 'name' => 'Роман'], 'user_567' => ['id' => 567, 'name' => 'Борис'], 'user_392' => ['id' => 392, 'name' => 'Артур'], ] */
keys()
Возвращает все ключи элементов коллекции.
1 2 3 4 5 6 7 8 9 10 11 12$cities = collect([ 'Москва' => ['country' => 'Россия'], 'Хельсинки' => ['country' => 'Финляндия'], 'Сан-Диего' => ['country' => 'США'], ]); $cities->keys()->all(); /* ['Москва', 'Хельсинки', 'Сан-Диего'] Такой же результат будет если сделать array_keys($cities->all()) */
sum()
Возвращает сумму элементов коллекции. Можно передать callback-функцию со своей логикой подсчёта суммы, либо же передать строку с ключом, значения которого нужно суммировать.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23$collection = collect([1, 2, 3, 4, 5, 4, 3, 2, 1]); /* Сумма все элементов */ $collection->sum(); // 25 /* Сумма элементов в многомерной коллекции (баланс пользователей) */ $users = collect([ ['id' => 1, 'name' => 'Роман', 'balance' => 95000, 'is_admin' => true], ['id' => 2, 'name' => 'Петр', 'balance' => 500], ['id' => 3, 'name' => 'Евгений', 'balance' => 1100], ['id' => 4, 'name' => 'Елизавета', 'balance' => 200], ['id' => 5, 'name' => 'Рената', 'balance' => 450], ]); $users->sum('balance'); // 97250 /* Найдем баланс пользователей, которые не являются администраторами */ $users->sum( fn($item) => ($item['is_admin'] ?? false) === false ? $item['balance'] : 0 ); // 2250
min()
Возвращает минимальное значение среди элементов коллекции. Можно передать callback-функцию со своей логикой определения наименьшего значения, либо же передать строку с ключом, по которому сравнивать элементы.
Противоположность метода max().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$numbers = collect([1, 6, 20]); /* Наименьшее значение */ $numbers->min(); // 1 /* Наименьшее значение, но не менее чем чем 3 */ $numbers->max(fn($item) => $item >= 3 ? $item : null); // 6 /* Наименьшее значение ключа */ $users = collect([ ['name' => 'Роман', 'age' => 23], ['name' => 'Денис', 'age' => 35], ['name' => 'Егор', 'age' => 14], ]); $users->min('age'); // 14
max()
Возвращает максимальное значение среди элементов коллекции. Можно передать callback-функцию со своей логикой определения наибольшего значения, либо же передать строку с ключом, по которому сравнивать элементы.
Противоположность метода min().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$numbers = collect([1, 6, 2, 20, 5, 3, 4]); /* Наибольшее значение */ $numbers->max(); // 20 /* Наибольшее значение, но не более чем 10 */ $numbers->max(fn($item) => $item <= 10 ? $item : null); // 6 /* Наибольшее значение ключа */ $users = collect([ ['name' => 'Роман', 'age' => 23], ['name' => 'Денис', 'age' => 35], ['name' => 'Егор', 'age' => 14], ]); $users->max('age'); // 35
median()
Возвращает значение медианы среди элементов коллекции. Можно не передавать никаких аргументов, а можно передать название ключа, по значениям которого сравнивать, или же callback-функцию.
$median = collect([1, 1, 2, 4])->median(); // 1.5
$users = collect([
['name' => 'Роман', 'age' => 23],
['name' => 'Денис', 'age' => 35],
['name' => 'Егор', 'age' => 14],
]);
$users->median('age'); // 23
mode()
Возвращает значение моды среди элементов коллекции. Можно не передавать никаких аргументов, а можно передать название ключа, по значениям которого сравнивать, или же callback-функцию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19$mode = collect([1, 2, 3])->mode(); // [1, 2, 3] $mode = collect([1, 1, 2, 4])->mode(); // [1] $users = collect([ ['name' => 'Роман', 'age' => 23], ['name' => 'Денис', 'age' => 35], ['name' => 'Ольга', 'age' => 33], ['name' => 'Сергей', 'age' => 28], ['name' => 'Дмитрий', 'age' => 35], ['name' => 'Павел', 'age' => 23], ['name' => 'Анна', 'age' => 24], ['name' => 'Егор', 'age' => 14], ]); $mode = $users->mode('age'); // [23, 35]
merge()
Объединяет коллекцию с переданным в аргументе массивом или другой коллекцией.
Если переданные элементы содержат числовые ключи, то они будут добавлены к исходной коллекции. Если же передаются элементы со строковыми ключами и таких ключи уже есть в исходной коллекции, то значения будут перезаписаны значениями передаваемых элементов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14$collection = collect([1, 2, 3, 4]); $merged = $collection->merge([5, 6, 7, 8]); $merged->all(); // [1, 2, 3, 4, 5, 6, 7, 8] $merged = $collection->merge([1, 2, 3, 4]); $merged->all(); // [1, 2, 3, 4, 1, 2, 3, 4] $collection = collect(['id' => 1, 'price' => 100]); $merged = $collection->merge(['price' => 200, 'discount' => false]); $merged->all(); // ['id' => 1, 'price' => 200, 'discount' => false]
mergeRecursive()
Объединяет коллекцию с переданным в аргументе массивом или другой коллекцией. Отличается от merge() тем, что значения элементов не будут перезаписываться, а будут помещены в совместный массив.
1 2 3 4 5 6$collection = collect(['id' => 1, 'price' => 100]); $merged = $collection->mergeRecursive(['id' => 2, 'price' => 200, 'discount' => false]); $merged->all(); // ['id' => [1, 2], 'price' => [100, 200], 'discount' => false]
replace()
Объединяет коллекцию с переданным в аргументе массивом или другой коллекцией, перезаписывая при этом повторяющиеся значения ключей.
Ведет себя аналогично методу merge(), однако, в дополнение к перезаписи соответствующих элементов строковыми ключами, метод replace() также перезапишет элементы в коллекции, которые имеют соответствующие числовые ключи.
1 2 3 4 5 6 7 8 9 10 11 12 13 14$collection = collect([1, 2, 3, 4]); $replaced = $collection->replace([5, 6, 7, 8]); $replaced->all(); // [1, 2, 3, 4, 5, 6, 7, 8] $replaced = $collection->replace([1, 2, 3, 4]); $replaced->all(); // [1, 2, 3, 4] $collection = collect(['id' => 1, 'price' => 100]); $replaced = $collection->replace(['price' => 200, 'discount' => false]); $replaced->all(); // ['id' => 1, 'price' => 200, 'discount' => false]
replaceRecursive()
Объединяет коллекцию с переданным в аргументе массивом или другой коллекцией, перезаписывая при этом повторяющиеся значения ключей.
От replace() отличается тем, что выполняет это действие рекурсивно (на вложенные массивы и коллекции).
1 2 3 4 5 6$collection = collect(['id' => 1, 'price' => 100, 'categories' => [1, 2, 3]]); $replaced = $collection->replaceRecursive(['price' => 200, 'discount' => false, 'categories' => [3 => 4]]); $replaced->all(); // ['id' => 1, 'price' => 200, 'discount' => false, 'categories' => [1, 2, 3, 4]]
union()
Объединяет коллекцию с переданным в аргументе массивом или другой коллекцией. От merge() и replace() отличается тем, что данные исходной коллекции не будут перезаписываться.
$user = collect(['id' => 1, 'name' => 'Роман', 'balance' => 5000]);
$newUser = $user->union(['balance' => 10000, 'is_subscribed' => true]);
$newUser->all();
// ['id' => 1, 'name' => 'Роман', 'balance' => 5000, 'is_subscribed' => true]
zip()
Объединяет все значения заданного массива со значениями исходной коллекции на соответствующем индексе.
$products = collect(['Стол', 'Стул', 'Шкаф']);
$prices = [5000, 3500, 8000, 9999];
// $prices = collect([5000, 3500, 8000, 9999]);
$products->zip($prices)->toArray();
// [['Стол', 5000], ['Стул', 3500], ['Шкаф', 8000], [null, 9999]]
collect()
Возвращает новый экземпляр коллекции с данными исходной коллекции. Результат этого метода будет идентичен, если просто склонировать коллекцию с помощью PHP оператора clone, за исключением ситуаций, когда необходимо преобразовать ленивую коллекцию в обычную (см. Ленивые коллекции).
$collectionA = collect([1, 2, 3]);
// Collection #1 { [1, 2, 3] }
$collectionB = $collectionA->collect();
// Collection #2 { [1, 2, 3] }
$collectionC = clone $collectionA;
// Collection #3 { [1, 2, 3] }
make()
Статический метод. Создает новый экземпляр коллекции. Чаще всего к нему прибегают при создании ленивых коллекций, в других случаях используют collect(), что, по сути, одно и тоже (см. Создание коллекции).
macro()
Статический метод. Позволяет регистрировать пользовательские методы коллекций (см. Расширение коллекций).
times()
Статический метод. Создает новую коллекцию путем выполнения callback-функции определенное количество раз.
/* Получим с пятью последними годами */
$currentYear = now()->year;
$collection = Collection::times(5,
fn($number) => $currentYear - $number
);
$collection->all();
// [2015, 2016, 2017, 2018, 2019]
nth()
Создаёт новую коллекцию каждые n элементов. Во втором аргумент можно указать отклонение от начала коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$collection = collect([ 'П', 'H', 'р', 'e', 'и', 'l', 'в', 'l', 'е', 'o', 'т', ]); $hello = $collection->nth(2); $hello->implode(''); // Привет $hello = $collection->nth(2, 1); $hello->implode(''); // Hello
pad()
Заполняет коллекцию переданным значением до определенной длины. Если указать отрицательное значение, то заполнение начнется сначала коллекции.
$collection = collect(['А', 'Б', 'В']);
$padded= $collection->pad(5, 0);
$padded->all();
// ['А', 'Б', 'В', 0, 0]
$padded = $collection->pad(-5, 0);
$padded->all();
// [0, 0, 'А', 'Б', 'В']
partition()
Делит элементы на две коллекции. В качестве аргумента принимает callback-функцию. Если эта callback-функция вернет true - то этот элемент пойдет в первую коллекцию, если false или ничего не вернет - то во вторую.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31$users = collect([ ['id' => 1, 'name' => 'Роман', 'is_admin' => true], ['id' => 2, 'name' => 'Борис', 'is_admin' => false], ['id' => 3, 'name' => 'Евгений', 'is_admin' => false], ['id' => 4, 'name' => 'Ксения', 'is_admin' => true], ['id' => 5, 'name' => 'Александр', 'is_admin' => false], ]); /** @var Collection $admins */ /** @var Collection $users */ [$admins, $users] = $users->partition( /* ^ можно использовать list() */ fn($value) => ($value['is_admin'] ?? false) === true ); $admins->all(); /* [ ['id' => 1, 'name' => 'Роман', 'is_admin' => true], ['id' => 4, 'name' => 'Ксения', 'is_admin' => true], ] */ $users->all(); /* [ ['id' => 2, 'name' => 'Борис', 'is_admin' => false], ['id' => 3, 'name' => 'Евгений', 'is_admin' => false], ['id' => 5, 'name' => 'Александр', 'is_admin' => false], ] */
tap()
Передает коллекцию callback-функции и возвращает объект этой коллекции. Можно делать различного рода операции и вычисления внутри callback-функции, при этом продолжить выполнение других методов цепным способом, так как tap() всегда возвращает объект коллекции.
$sum = null;
$collection = collect([1, 2, 3, 4, 5, 6, 7, 9])
->tap(function (Collection $collection) use (&$sum) {
$sum = $collection->sum();
Log::debug("Сумма элементов коллекции: {$sum}.");
});
echo $sum; // 37
pipe()
Передает коллекцию в заданную функцию и возвращает результат.
От tap() отличается тем, что в tap() - неважно, что возвращает callback-функция - всегда будет возвращен объект коллекции. Метод pipe() же возвращает результат callback-функции - это может быть как объект, так и другое значение.
Удобно использовать, когда нужно выполнить или абстрагировать какой-то код в процессе манипуляции над коллекцией.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17$collection = collect([1, 2, 3, 4, 5]); /** @var Collection $piped */ $piped = $collection->pipe(function (Collection $collection) { if ($collection->sum() < 10) { Log::debug('Сумма коллекции меньше 10, возвращаем исходную коллекцию.'); return $collection; } Log::debug('Сумма коллекции больше или равно 10, возвращаем перевернутую коллекцию.'); return $collection->reverse(); }); $piped->all(); // [5, 4, 3, 2, 1]
reverse()
Меняет порядок элементов в коллекции в обратную сторону (зеркалит коллекцию), сохраняя при этом ключи.
$collection = collect(['а', 'б', 'в', 'г', 'д']);
$reversed = $collection->reverse();
$reversed->all();
// ['д', 'г', 'в', 'б', 'а']
sort()
Сортирует коллекцию по возрастанию. Сохраняет ключи (если нужно сбросить ключи, после сортировки примените к коллекции метод values()). Противоположность метода sortDesc().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18$collection = collect([5, 3, 1, 2, 4]); /* По возрастанию */ $sorted = $collection->sort()->values(); $sorted->all(); // [1, 2, 3, 4, 5] /* Сначала те, которые делятся на 2 без остатка */ $sorted = $collection->sort(function ($a, $b) { if ($a % 2 === $b % 2) { return $a <=> $b; } return $a % 2 === 0 ? -1 : 1; }); $sorted->all(); // [2, 4, 1, 3, 5]
sort() в своей работе вызывает uasort(), о сортировке через которую можно прочитать в документации к PHP.
sortDesc()
Сортирует коллекцию в обратном порядке (от большего к меньшему). Противоположность метода sort(), однако, в отличие от которой, не может принимать callback-функцию в качестве аргумента.
$collection = collect([1, 5, 3, 2, 4]);
$sorted = $collection->sortDesc()->values();
$sorted->all();
// [5, 4, 3, 2, 1]
sortBy(), sortByDesc()
Сортируют коллекцию по значениям переданного ключа. Сохраняют ключи (если нужно сбросить ключи, после сортировки примените к коллекции метод values()).
sortBy() сортирует от меньшего к большему, sortByDesc() - наоборот.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29$products = collect([ ['name' => 'Стул', 'colors' => ['Чёрный', 'Коричневый']], ['name' => 'Стол', 'colors' => ['Чёрный']], ['name' => 'Шкаф', 'colors' => ['Белый', 'Чёрный', 'Коричневый']], ]); /* Отсортируем по количеству доступных цветов */ // Запишем анонимную функцию в переменную (для удобства демонстрации примера) $sortByColorsCallback = fn($product, $key) => count($product['colors']); $products->sortBy($sortByColorsCallback)->values()->all(); /* [ ['name' => 'Стол', 'colors' => ['Чёрный']], ['name' => 'Стул', 'colors' => ['Чёрный', 'Коричневый']], ['name' => 'Шкаф', 'colors' => ['Белый', 'Чёрный', 'Коричневый']], ] */ /* Тоже самое, только в обратном порядке */ $products->sortByDesc($sortByColorsCallback)->values()->all(); /* [ ['name' => 'Шкаф', 'colors' => ['Белый', 'Чёрный', 'Коричневый']], ['name' => 'Стул', 'colors' => ['Чёрный', 'Коричневый']], ['name' => 'Стол', 'colors' => ['Чёрный']], ] */
sortKeys(), sortKeysDesc()
Сортируют элементы коллекции по их ключам. sortKeys() сортирует от меньшего к большему, sortKeysDesc() - наоборот.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23$collection = collect([ 999 => 'три', 111 => 'один', 555 => 'два', ]); $collection->sortKeys()->all(); /* [ 111 => 'один', 555 => 'два', 999 => 'три', ] */ $collection->sortKeysDesc()->all(); /* [ 999 => 'три', 555 => 'два', 111 => 'один', ] */
values()
Сбрасывает ключи у элементов коллекции и возвращает результат.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19$collection = collect([ 11 => 'один', 12 => 'два', 13 => 'три', 14 => 'четыре', 15 => 'пять', ])->values(); $collection->all(); // ['один', 'два', 'три', 'четыре', 'пять'] $collection = collect([ 'key1' => 'один', 'key2' => 'два', 'key3' => 'три', ])->values(); $collection->all(); // ['один', 'два', 'три']
take()
Возвращает новую коллекцию с заданным числом элементов (обрезает коллекцию). Можно передать отрицательное значение, тогда будут возвращены элементы с конца коллекции. Противоположность метода skip().
Сохраняет ключи, если нужно их сбросить - примените к коллекции метод values().
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
$collection->take(4)->all();
// [1, 2, 3, 4]
$collection->take(-3)->values()->all();
// [8, 9, 10]
takeUntil()
Перебирает элементы коллекции с начала и оставляя все элементы, пока callback-функция не вернет true, после чего возвращает новую коллекцию. Является противоположностью метода takeWhile().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26$users = collect([ ['id' => 1, 'name' => 'Вениамин', 'born_at' => 1987], ['id' => 2, 'name' => 'Петр', 'born_at' => 1993], ['id' => 3, 'name' => 'Елена', 'born_at' => 1995], ['id' => 4, 'name' => 'Игорь', 'born_at' => 1996], ['id' => 5, 'name' => 'Ксения', 'born_at' => 1999], ['id' => 6, 'name' => 'Ирина', 'born_at' => 2003], ['id' => 7, 'name' => 'Екатерина', 'born_at' => 2003], ['id' => 8, 'name' => 'Алексей', 'born_at' => 2006], ]); /* Оставим только тех, кто родился в 20 веке */ $adultUsers = $users->takeUntil( fn($value) => $value['born_at'] >= 2000 ); $adultUsers->all(); /* [ ['id' => 1, 'name' => 'Вениамин', 'born_at' => 1987], ['id' => 2, 'name' => 'Петр', 'born_at' => 1993], ['id' => 3, 'name' => 'Елена', 'born_at' => 1995], ['id' => 4, 'name' => 'Игорь', 'born_at' => 1996], ['id' => 5, 'name' => 'Ксения', 'born_at' => 1999], ] */
Если коллекция одномерная, то можно не передавать callback-функцию, а передать значение, до наступления которого будут оставлены все элементы:
$collection = collect(['один', 'два', 'три', 'четыре', 'пять']);
$subset = $collection->takeUntil('три');
$subset->all();
// ['один', 'два']
takeWhile()
Перебирает элементы коллекции с начала и оставляя все элементы, пока callback-функция не вернет false, после чего возвращает новую коллекцию. Является противоположностью метода takeUntil().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26$users = collect([ ['id' => 1, 'name' => 'Вениамин', 'born_at' => 1987], ['id' => 2, 'name' => 'Петр', 'born_at' => 1993], ['id' => 3, 'name' => 'Елена', 'born_at' => 1995], ['id' => 4, 'name' => 'Игорь', 'born_at' => 1996], ['id' => 5, 'name' => 'Ксения', 'born_at' => 1999], ['id' => 6, 'name' => 'Ирина', 'born_at' => 2003], ['id' => 7, 'name' => 'Екатерина', 'born_at' => 2003], ['id' => 8, 'name' => 'Алексей', 'born_at' => 2006], ]); /* Оставим только тех, кто родился в 20 веке */ $minorUsers = $users->takeWhile( fn($value) => $value['born_at'] < 2000 ); $minorUsers->all(); /* [ ['id' => 1, 'name' => 'Вениамин', 'born_at' => 1987], ['id' => 2, 'name' => 'Петр', 'born_at' => 1993], ['id' => 3, 'name' => 'Елена', 'born_at' => 1995], ['id' => 4, 'name' => 'Игорь', 'born_at' => 1996], ['id' => 5, 'name' => 'Ксения', 'born_at' => 1999], ] */
skip()
Возвращает новую коллекцию, пропустив (удалив) первые n элементов. Противоположность метода take().
$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()
Перебирает элементы коллекции с начала и пропуская (удаляя) все элементы, пока callback-функция не вернет true, после чего возвращает новую коллекцию. Противоположность метода skipWhile().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24$users = collect([ ['id' => 1, 'name' => 'Вениамин', 'born_at' => 1987], ['id' => 2, 'name' => 'Петр', 'born_at' => 1993], ['id' => 3, 'name' => 'Елена', 'born_at' => 1995], ['id' => 4, 'name' => 'Игорь', 'born_at' => 1996], ['id' => 5, 'name' => 'Ксения', 'born_at' => 1999], ['id' => 6, 'name' => 'Ирина', 'born_at' => 2003], ['id' => 7, 'name' => 'Екатерина', 'born_at' => 2003], ['id' => 8, 'name' => 'Алексей', 'born_at' => 2006], ]); /* Оставим только тех, кто родился в 21 веке */ $minorUsers = $users->skipUntil( fn($value) => $value['born_at'] >= 2000 ); $minorUsers->all(); /* [ ['id' => 6, 'name' => 'Ирина', 'born_at' => 2003], ['id' => 7, 'name' => 'Екатерина', 'born_at' => 2003], ['id' => 8, 'name' => 'Алексей', 'born_at' => 2006], ] */
Если коллекция одномерная, то можно не передавать callback-функцию, а передать значение, до наступления которого будут удалены все элементы:
$collection = collect(['один', 'два', 'три', 'четыре', 'пять']);
$skipped = $collection->skipUntil('три');
$skipped->all();
// ['три', 'четыре', 'пять']
skipWhile()
Перебирает элементы коллекции с начала и пропуская (удаляя) все элементы, пока callback-функция не вернет false, после чего возвращает новую коллекцию. Противоположность метода skipUntil().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24$users = collect([ ['id' => 1, 'name' => 'Вениамин', 'born_at' => 1987], ['id' => 2, 'name' => 'Петр', 'born_at' => 1993], ['id' => 3, 'name' => 'Елена', 'born_at' => 1995], ['id' => 4, 'name' => 'Игорь', 'born_at' => 1996], ['id' => 5, 'name' => 'Ксения', 'born_at' => 1999], ['id' => 6, 'name' => 'Ирина', 'born_at' => 2003], ['id' => 7, 'name' => 'Екатерина', 'born_at' => 2003], ['id' => 8, 'name' => 'Алексей', 'born_at' => 2006], ]); /* Оставим только тех, кто родился в 21 веке */ $minorUsers = $users->skipWhile( fn($value) => $value['born_at'] < 2000 ); $minorUsers->all(); /* [ ['id' => 6, 'name' => 'Ирина', 'born_at' => 2003], ['id' => 7, 'name' => 'Екатерина', 'born_at' => 2003], ['id' => 8, 'name' => 'Алексей', 'born_at' => 2006], ] */
slice()
Возвращает коллекцию, начиная с переданного индекса (остальные элементы будут удалены). Ключи при этом сохранятся (если не нужно - примените к коллекции метод values()).
Если нужно ограничить кол-во получаемых элементов, можно передать число с необходимым количеством во второй аргумент вызываемого метода.
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
$slice = $collection->slice(4);
$slice->values()->all();
// [5, 6, 7, 8, 9, 10]
$slice = $collection->slice(2, 3);
$slice->values()->all();
// [3, 4, 5]
splice()
Возвращает элементы коллекции, начиная с переданного индекса. От метода slice() отличается тем, что удаляет полученные элементы из исходной коллекции.
Если нужно ограничить кол-во получаемых элементов, можно передать число с необходимым количеством во второй аргумент вызываемого метода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18$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]
Кроме этого, метод принимает 3-й аргумент - значение (или массив значений), которые будут подставлены в исходную коллекцию вместо удаленных элементов.
1 2 3 4 5 6 7 8 9 10 11$hello = collect(['Привет', ', ', 'Роман', '!']); echo $hello->implode(''); // Привет, Роман! $userName = $hello->splice(2, 1, ['Уважаемый ', 'посетитель']); $userName->all(); // ['Роман'] echo $hello->implode(''); // Привет, Уважаемый посетитель!
split()
Разделяет коллекцию на несколько частей.
$collection = collect([1, 2, 3, 4, 5]);
$groups = $collection->split(3);
$groups->toArray();
// [[1, 2], [3, 4], [5]]
when()
Выполняет callback-функцию если в первом аргументе было передано true. Противоположность метода unless().
В качестве третьего аргумента можно передать ещё одну callback-функцию, которая выполнится по умолчанию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22$collection = collect(); $collection->when(true, function (Collection $collection) { /* Этот код выполнится, так как мы передаем true */ return $collection->push('один'); }); $collection->when(false, function (Collection $collection) { /* Этот код НЕ выполнится, так как мы передаем false */ return $collection->push('два'); }); $collection->when(false, function (Collection $collection) { /* Этот код НЕ выполнится, так как мы передаем false */ return $collection->push('три'); }, function (Collection $collection) { /* Но при этом выполнится этот код (по умолчанию) */ return $collection->push('четыре'); }); $collection->all(); // ['один', 'четыре']
unless()
Выполняет callback-функцию если в первом аргументе было передано false. Противоположность метода when().
В качестве третьего аргумента можно передать ещё одну callback-функцию, которая выполнится по умолчанию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22$collection = collect(); $collection->unless(false, function (Collection $collection) { /* Этот код выполнится, так как мы передаем false */ return $collection->push('один'); }); $collection->unless(true, function (Collection $collection) { /* Этот код НЕ выполнится, так как мы передаем true */ return $collection->push('два'); }); $collection->unless(true, function (Collection $collection) { /* Этот код НЕ выполнится, так как мы передаем true */ return $collection->push('три'); }, function (Collection $collection) { /* Но при этом выполнится этот код (по умолчанию) */ return $collection->push('четыре'); }); $collection->all(); // ['один', 'четыре']
whenNotEmpty(), unlessEmpty()
Выполняет callback-функцию если коллекция не пустая. Противоположность методов whenEmpty(), unlessNotEmpty().
В качестве второго аргумента можно передать ещё одну callback-функцию, которая выполнится по умолчанию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26$collection = collect(); $collection->whenNotEmpty(function (Collection $collection) { /* Этот код НЕ выполнится, так как $collection пустая */ return $collection->push('один'); }); // [] $collection->unlessEmpty(function (Collection $collection) { /* Этот код НЕ выполнится, так как $collection пустая */ return $collection->push('два'); }, function (Collection $collection) { /* Но при этом выполнится этот код (код по умолчанию) */ return $collection->push('три'); }); $collection->all(); // ['три'] $collection->whenNotEmpty(function (Collection $collection) { /* Этот код выполнится, так как $collection не пустая */ return $collection->push('четыре'); }); $collection->all(); // ['три', 'четыре']
whenEmpty(), unlessNotEmpty()
Выполняет callback-функцию если коллекция пустая. Противоположность методов whenNotEmpty(), unlessEmpty().
В качестве второго аргумента можно передать ещё одну callback-функцию, которая выполнится по умолчанию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26$collection = collect(); $collection->whenEmpty(function (Collection $collection) { /* Этот код выполнится, так как $collection пустая */ return $collection->push('один'); }); // ['один'] $collection->unlessNotEmpty(function (Collection $collection) { /* Этот код НЕ выполнится, так как $collection не пустая */ return $collection->push('два'); }, function (Collection $collection) { /* Но при этом выполнится этот код (код по умолчанию) */ return $collection->push('три'); }); $collection->all(); // ['один', 'три'] $collection->whenEmpty(function (Collection $collection) { /* Этот код НЕ выполнится, так как $collection не пустая */ return $collection->push('четыре'); }); $collection->all(); // ['один', 'три']
wrap()
Статический метод. Все значения, которые в него передаются - обернутся в коллекцию. Если передать коллекцию, то ничего не произойдет и вернется она же. Противоположность метода unwrap().
1 2 3 4 5 6 7 8 9 10Collection::wrap(null)->all(); // Collection { [] } Collection::wrap([]); // Collection { [] } Collection::wrap(''); // Collection { [''] } Collection::wrap(1); // Collection { [1] } Collection::wrap('строка'); // Collection { ['строка'] } Collection::wrap(true); // Collection { [true] } Collection::wrap(['строка', 'в', 'массиве']); // Collection { ['строка', 'в', 'массиве'] } Collection::wrap(collect(['строка', 'в', 'коллекции'])); // Collection { ['строка', 'в', 'коллекции'] }
unwrap()
Статический метод. Если в него передать коллекцию, то вернется преобразованный массив (через метод all()). В остальных случаях вернется то, что изначально передавалось. Противоположность метода wrap().
Collection::unwrap(null); // null
Collection::unwrap(1); // 1
Collection::unwrap('строка'); // строка
Collection::unwrap(['массив']); // ['массив']
Collection::unwrap(collect(['коллекция'])); // ['коллекция']
toJson()
Конвертирует элементы коллекции в формат JSON.
1 2 3 4 5 6 7 8$collection = collect([ ['id' => 1, 'name' => 'Роман'], ['id' => 2, 'name' => 'Анна'], ['id' => 3, 'name' => 'Борис'], ]); echo $collection->toJson(); // [{"id":1,"name":"\u0420\u043e\u043c\u0430\u043d"},{"id":2,"name":"\u0410\u043d\u043d\u0430"},{"id":3,"name":"\u0411\u043e\u0440\u0438\u0441"}]
dump()
Выводит информацию о переменных коллекции (используется для отладки).
1 2 3 4 5 6 7 8 9 10 11 12 13$collection = collect([ 'Коллекции', 'это', 'просто', ]); $collection->dump(); /* Collection { ['Коллекции', 'это', 'просто'] } */
dd()
Выводит информацию о переменных коллекции и завершает выполнение программы. По факту, этот метод делает dump(), а затем завершает скрипт с помощью die().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15$collection = collect([ 'Коллекции', 'это', 'просто', ]); $collection->dd(); /* Collection { ['Коллекции', 'это', 'просто'] } */ echo 'Hey!'; // Этот код уже не выполнится, так как dd() завершает работу программы
Расширение коллекций
Коллекциям можно добавлять пользовательские методы с помощью статичного метода macro(), который будет вызван перед выполнением метода.
В примере ниже мы создадим новый метод toUpper(), который будет преобразовывать все значения элементов коллекции в верхний регистр.
Collection::macro('toUpper', function () {
return $this->map(
fn($item, $key) => Str::upper($item)
);
});
$collection = collect(['один', 'два', 'три']);
$collection->toUpper()->all();
// ['ОДИН', 'ДВА', 'ТРИ']
Хорошей практикой будет регистрировать ваши методы в провайдерах.
Например, можно сделать новый провайдер CollectionServiceProvider выполнив в консоли следующую команду: php artisan make:provider CollectionServiceProvider, после чего в методе register() зарегистрировать все пользовательские методы коллекций способом, который указан выше.
Расширение коллекций моделей Eloquent
Если вам нужно создать какой-то специфичный метод только для одной/нескольких моделей, можно поступить следующим образом:
- Создать новый класс коллекции, который будет наследоваться от базового класса Collection. Хорошим вариантом будет сделать папку /app/Collections.
Пример содержимого файла UserCollection.php (пользовательской коллекции для модели User):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22<?php namespace App\Collections; use Illuminate\Support\Collection; /** * Пользовательская коллекция для модели \App\User. */ class UserCollection extends Collection { /** * Фильтрует коллекцию. Оставляет только пользователей-администраторов. * * @return mixed */ public function allAdmins() { return $this->filter->is_admin; // Используются сообщения высшего порядка, но можно и прибегнуть к методам } }
- В самой модели (в нашем примере используется модель User) переопределить публичный метод newCollection().
public function newCollection(array $models = [])
{
return new UserCollection($models);
}
На этом всё. Теперь, при создании экземпляра этой модели, или же при получении её из БД, можно применять пользовательский метод allAdmins().
1 2 3$users = User::all(); $users->allAdmins()->toArray(); // Вернется коллекциями с пользователями, у которых is_admin = true
Сообщения высшего порядка
Коллекции в Laravel поддерживают сообщения высшего порядка (higher order messages), которые упрощают выполнение каких-то общих действий и делает ваш код ещё читабельнее.
Подробно на этом разделе останавливаться не будем - это тема для отдельного туториала. Если говорить вкратце, то каждое сообщение высшего порядка может быть доступно как динамическое свойство в экземпляре коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20/* Пример 1 */ $users = collect([ ['id' => 1, 'name' => 'Илья', 'age' => 35], ['id' => 2, 'name' => 'Роман', 'age' => 23], ['id' => 3, 'name' => 'Глеб', 'age' => 84], ['id' => 4, 'name' => 'Максим', 'age' => 14], ]); echo $users->sum->age; // 156 /* Пример 2 */ $employees->reject(function ($employee) { return $employee->isRetired(); })->each(function ($employee) { $employee->sendPayment(); }); // Используя сообщения высшего порядка: $employees->reject->isRetired()->each->sendPayment();
Ленивые коллекции
Позволяют работать с большими объемами данных, сохраняя при этом небольшое потребление памяти. Использует генераторы PHP.
1 2 3 4 5 6 7 8 9 10 11 12 13 14//$hugeCollection = Collection::times(1 * 1000000); // Создается //$hugeCollection = Collection::times(10 * 1000000); // Ошибка: Allowed memory size of 536870912 bytes exhausted $hugeCollection = LazyCollection::times(10 * 1000000); // Создается $powed = $hugeCollection->map( fn($number) => $number ** 2 ); $powed->all();
Создание ленивой коллекции
Чтобы создать экземпляр ленивой коллекции, необходимо передать функцию PHP генератора в метод make().
$hugeCollection = LazyCollection::make(function () {
for ($i = 0; $i < 10000000; $i++) {
yield $i;
}
});
$hugeCollection->each(function ($item) {
echo "$item <br />";
});
Методы ленивой коллекции
В ленивой коллекции доступны почти все методы обычной коллекции, за исключением тех, которые изменяют исходную коллекцию: shift(), pop(), prepend() и др.
Кроме того, ленивые коллекции имеют ряд методов, которые не представлены в обычной коллекции:
tapEach()
При использовании метода each(), вызов его callback-функции по отношению к элементам коллекции идёт сразу. tapEach() же вызывает свой callback только если это понадобится.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28$lazyCollection = LazyCollection::make(function () { for ($i = 0; $i < 3; $i++) { yield $i; } }); /* Обычный each() */ $lazyCollection->each(function ($item) { echo 'Этот код выполнится и покажется на экран.<br />'; }); /* Этот код выполнится и покажется на экран. Этот код выполнится и покажется на экран. Этот код выполнится и покажется на экран. */ /* tapEach() */ $lazyCollection = $lazyCollection->tapEach(function ($item) { echo 'Этот код выполнится только по требованию.<br />'; }); // (ничего) $lazyCollection->all(); /* Этот код выполнится только по требованию. Этот код выполнится только по требованию. Этот код выполнится только по требованию. */
remember()
Возвращает новую ленивую коллекцию, которая запомнит все значения, которые уже были перечислены, и не получит их снова при повторном перечислении коллекции.
$users = User::cursor()->remember();
// запросы в БД не делаются
$users->take(5)->all();
// Выполнится запрос и 5 первых пользователей будут взяты из БД
$users->take(20)->all();
// Первые 5 пользователей будут взяты из кэша, остальные - из БД
Коллекции или массивы?
Несмотря на то, что использовать коллекции очень удобно, это не означает, что нужно полностью отказываться от использования массивов [].
Исходя из моего опыта, я пришел к следующему выводу:
- Если вы не создавали коллекцию, а получили её откуда-то - не переводите без надобности в массив.
- Держитесь принципа KISS (Keep It Simple Stupid - делайте вещи проще). Если вам нужно произвести какую-то простую операцию - не стоит создавать объект массива - решите эту простую задачу средствами PHP.
/* Не стоит лишний раз создавать экземпляр коллекции */
// $numbers = collect([1, 2, 3]);
// $sum = $numbers->sum();
/* Сделайте выбор в пользу более простого варианта */
$numbers = [1, 2, 3];
$sum = array_sum($numbers);
// 6
- Возможность массового использования коллекций зависит также и от вашей команды. Все ли разработчики, которые работают с вами, хорошо владеют коллекциями и легко смогут понять ваш код?
Источник: Laravel.com
Понравилось прочитанное?
Дайте мне «пять», кликнув раз, или же поаплодируйте быстрыми нажатиями, чтобы показать, насколько вам понравился материал.
Комментарии