cloud-castle / collection
Коллекции для PHP 8.1+: цепочечный fluent-API над массивами, ленивые коллекции (генераторы, экономия памяти), higher-order messages, макросы, dot-доступ и сериализация в JSON/массив. Суперсет API illuminate/collections.
Requires
- php: >=8.1
- cloud-castle/serialize: >=1.0
Requires (Dev)
- deptrac/deptrac: ^3.0 || ^4.0
- doctrine/collections: ^2.1
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanhazstring/composer-unused: ^0.9
- illuminate/collections: ^10.0 || ^11.0
- infection/infection: ^0.29 || ^0.33
- loophp/collection: ^7.0
- php-parallel-lint/php-parallel-lint: ^1.4
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- ramsey/collection: ^2.0
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- vimeo/psalm: ^6.0
- webmozart/assert: ^1.11
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Collection
Иммутабельная флюентная коллекция для PHP 8.1+: 113 методов в стиле Laravel Collection (map, filter, reduce, pluck, groupBy, flatten и др.), ленивые коллекции (потоковая обработка в O(1) памяти), макросы и higher-order messages, строгая типизация и иммутабельность по умолчанию. Нулевые внешние зависимости.
Установка
composer require cloud-castle/collection
Требуется PHP 8.1+.
Быстрый старт
<?php
use CloudCastle\Collection\Collection;
$result = (new Collection([1, 2, 3, 4, 5, 6]))
->map(fn (int $x): int => $x * 2) // [2,4,6,8,10,12]
->filter(fn (int $x): bool => $x % 3 === 0) // [6,12]
->values()
->all();
// Исходная коллекция не мутирует — каждый шаг возвращает новый экземпляр.
$users = new Collection([
['name' => 'Ann', 'role' => 'admin'],
['name' => 'Bob', 'role' => 'user'],
]);
$byRole = $users->groupBy('role');
$names = $users->pluck('name')->all(); // ['Ann', 'Bob']
$admin = $users->firstWhere('role', 'admin');
Возможности
- 113 методов в стиле Laravel Collection:
map,filter,reduce,pluck,groupBy,flatten,collapse,sort*,chunk,zipи др. - Иммутабельность по умолчанию: преобразования возвращают новый экземпляр, исходная коллекция неизменна — безопасно для разделяемого состояния.
- Строгая типизация:
firstOrFail/soleбросают исключение вместо тихогоnull; предсказуемые типы возврата (static). - Ленивые коллекции (
LazyCollection): потоковый конвейер на генераторах — обработка бесконечных и огромных последовательностей в O(1) памяти (->lazy(),LazyCollection::range(),make()). - Макросы и higher-order messages — расширяемость как в
illuminate:Collection::macro()/mixin()добавляют методы в рантайме, а прокси-свойства ($users->map->name,$c->each->run()) заменяют однотипные замыкания. - Нулевые внешние зависимости — в отличие от
illuminate/collections, тянущего контракты и macroable фреймворка.
Коротко
Неизменяемая коллекция с богатым (113 методов) Laravel-подобным API, строгими
отказами, ленивыми коллекциями (потоковая обработка в O(1) памяти),
макросами и higher-order messages — при нулевых зависимостях. По
функционалу это полный суперсет: перекрывает всё, что есть у illuminate
(рич-набор + макросы + HOM), плюс ленивость loophp, иммутабельность и
строгие отказы — и всё без внешних зависимостей. На типовом конвейере
map→filter быстрее illuminate.
Сравнение с аналогами
Все таблицы ниже сгенерированы автоматически из честных сравнительных
тестов (benchmarks/compare.php) на ОДИНАКОВОЙ операции для всех аналогов,
PHP 8.1.34, без Xdebug.
1. Функциональность
| Возможность | 🏆 CloudCastle | illuminate | doctrine | ramsey | loophp | array_*¹ |
|---|---|---|---|---|---|---|
| Флюентный конвейер map/filter/reduce | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Богатый набор (pluck/groupBy/flatten, 100+ методов) | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| Иммутабельность по умолчанию | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
| Строгий отказ (firstOrFail/sole) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Ленивые коллекции (потоковая обработка, O(1) память) | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| Макросы и higher-order messages (расширяемость) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Нулевые внешние зависимости | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ |
| Всего | 🏆 7 | 6 | 2 | 2 | 4 | 2 |
2. Безопасность и корректность
| Свойство | 🏆 CloudCastle | illuminate | doctrine | ramsey | loophp | array_*¹ |
|---|---|---|---|---|---|---|
| Иммутабельность (map не мутирует источник) | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
| Строгий отказ вместо тихого null | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Без зависимости от фреймворка | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| Предсказуемый тип возврата (static) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Всего | 🏆 4 | 3 | 2 | 2 | 3 | 2 |
3. Производительность
Конвейер map→filter→values над 100 элементами, 100 000 раз (минимум из 4).
| Решение | Время (мс) | Итог |
|---|---|---|
| array_*¹ | 1 045 | базовый уровень (не библиотека) |
| 🏆 CloudCastle | 1 136,2 | быстрейшее среди библиотек |
| doctrine | 1 200,2 | аналог |
| illuminate | 1 486,4 | аналог |
| ramsey | 5 627,4 | аналог |
| loophp | 7 884 | аналог |
4. Потребление памяти
Инкрементальный пик конвейера на 500 000 элементов (изолированный процесс).
| Решение | Пиковая память (KB) | Итог |
|---|---|---|
| 🏆 loophp | 8 721 | легчайшее среди библиотек |
| array_*¹ | 31 748 | базовый уровень (не библиотека) |
| doctrine | 31 805 | аналог |
| CloudCastle | 31 985 | аналог |
| ramsey | 49 242 | аналог |
| illuminate | 49 739 | аналог |
¹ Базовый уровень (нативные вызовы/примитивы без полноты решения) показан для контекста и не претендует на победу среди библиотек-аналогов.
О памяти честно. Замер — инкрементальный пик энергичного конвейера на 500 000 элементов в изолированном процессе. Энергичный
Collectionнаравне с нативными массивами иdoctrine, экономнееilluminate/ramseyв ~1,5 раза;loophpлегче за счёт ленивости. Но для потоковой обработки у CloudCastle теперь естьLazyCollection— она даёт ту же O(1) память, что иloophp(см. пример ниже), так что по памяти на стриминге пакет не уступает.
Ленивые коллекции (потоковая обработка)
use CloudCastle\Collection\LazyCollection;
// Конвейер над бесконечным диапазоном — берётся только нужное, память O(1):
LazyCollection::range(1, PHP_INT_MAX)
->map(fn (int $x): int => $x * 2)
->filter(fn (int $x): bool => $x % 3 === 0)
->take(5)
->all(); // [6, 12, 18, 24, 30]
// Мост из энергичной коллекции и обратно:
(new Collection([1, 2, 3, 4, 5, 6]))->lazy()
->filter(fn (int $x): bool => $x % 2 === 0)
->collect(); // снова Collection([2, 4, 6])
Макросы и higher-order messages
Расширяемость на уровне illuminate — но без зависимости от фреймворка.
use CloudCastle\Collection\Collection;
// Макрос — добавить свой метод в рантайме (замыкание связывается с $this):
Collection::macro('sumSquares', function (): int {
return (int) $this->map(fn (int $x): int => $x * $x)->sum();
});
(new Collection([1, 2, 3]))->sumSquares(); // 14
// mixin — подмешать набор методов из объекта; hasMacro/flushMacros — управление.
Collection::hasMacro('sumSquares'); // true
// Higher-order messages — краткая запись однотипных замыканий:
$users = new Collection([
(object) ['name' => 'Ann', 'age' => 30],
(object) ['name' => 'Bob', 'age' => 25],
]);
$users->map->name; // Collection(['Ann', 'Bob']) — как map(fn ($u) => $u->name)
$users->sum->age; // 55 — как sum(fn ($u) => $u->age)
$users->each->name; // вызов метода: $c->each->save() и т.п.
Поддерживаемые HOM-свойства: average, avg, contains, countBy, doesntContain,
each, every, filter, first, flatMap, groupBy, keyBy, map, max, min,
partition, reject, skipUntil, skipWhile, some, sortBy, sortByDesc, sum,
takeUntil, takeWhile, unique.
Плюсы, минусы и когда применять
Сильные стороны:
- Полный суперсет по функционалу — всё, что есть у
illuminate(рич-набор из 113 методов + макросы + higher-order messages), плюс ленивые коллекции (какloophp), иммутабельность и строгие отказы — и всё без внешних зависимостей. - Иммутабельность по умолчанию —
map/filterне мутируют источник (уilluminate/doctrineколлекции мутабельны). - Ленивая потоковая обработка —
LazyCollectionобрабатывает бесконечные/огромные наборы в O(1) памяти (какloophp), но с тем же строгим, иммутабельным API. - Расширяемость — макросы,
mixinи higher-order messages как вilluminate. - Скорость — быстрее
illuminate,ramsey,loophpна энергичном конвейере. - Нулевые зависимости — не тянет фреймворк.
Слабые стороны (честно):
- Экосистема и адаптация меньше, чем у
illuminate(де-факто стандарт в Laravel): меньше сторонних макро-пакетов и примеров под конкретный фреймворк. - API близок к Laravel, но не 1:1 — при миграции возможны расхождения в отдельных сигнатурах.
- Пиковая память энергичного конвейера выше, чем у ленивого
loophp(для стриминга используйтеLazyCollection— там память O(1)).
Когда применять. Неизменяемые и/или потоковые преобразования данных в доменном
коде, где важны предсказуемость, строгость, ленивость, расширяемость и отсутствие
зависимостей — как вне Laravel, так и рядом с ним. illuminate остаётся удобнее
лишь при тесной интеграции с экосистемой Laravel и готовыми пакетами под неё.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
Полный список команд с описаниями: composer run-script --list.
Документация
- Репозиторий: https://gitverse.ru/cloud-castle/collection
- История изменений: CHANGELOG.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano