cloudcastle/collection

Production-ready PHP 8.1+ package (CloudCastle Collection).

Maintainers

Package info

github.com/cloudcastle-apps/collection

Homepage

Documentation

pkg:composer/cloudcastle/collection

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.1.0 2026-07-16 17:04 UTC

README

Version PHP Version License Total Downloads Monthly Downloads Packagist Stars Dependents Suggesters Security Advisories

Quality CodeQL GitHub Stars GitHub Forks GitHub Issues Latest Release Last Commit Contributors

Coverage Mutation MSI OpenSSF Scorecard PHPStan Psalm Code Style

Коллекции для PHP 8.1+ со строгой семантикой сравнений: contains('1')contains(1), строка из данных никогда не выполняется как код, JSON падает исключением, а не тихим false. ~85 методов — функциональный суперсет четырёх популярных библиотек, ноль runtime-зависимостей.

Установка

composer require cloudcastle/collection

Требуется PHP 8.1+. Runtime-зависимостей нет.

Быстрый старт

<?php

use CloudCastle\Collection\Collection;

$orders = Collection::make([
    ['id' => 1, 'customer' => 'alice', 'status' => 'paid',    'total' => 150],
    ['id' => 2, 'customer' => 'bob',   'status' => 'pending', 'total' => 70],
    ['id' => 3, 'customer' => 'alice', 'status' => 'paid',    'total' => 220],
]);

// Цепочки: фильтр → группировка → агрегат → сортировка
$report = $orders
    ->where('status', 'paid')          // строгое сравнение: '1' не пройдёт за 1
    ->groupBy('customer')
    ->map(static fn ($group) => $group->sum('total'))
    ->sortDesc();                      // ['alice' => 370]

// Статистика
$orders->pluck('total')->avg();        // 146.66…
$orders->pluck('total')->median();     // 150

// Безопасный JSON-цикл
$json = $orders->toJson();                    // исключение вместо тихого false

// сериализация через cloudcastle/serialize: JSON по умолчанию,
// PHP-формат с белым списком классов, DoS-лимиты, анти-POP
$payload = $orders->toSerialized();
$restored = Collection::fromSerialized($payload);
$restored = Collection::fromJson($json);      // исключение на битом JSON, лимит глубины

// Строгость как фича: классические ловушки PHP исключены
Collection::make([0, '1', null])->contains('admin'); // false (а не true, как при ==)
Collection::make([1, '1', true])->unique()->count(); // 3 (типы не схлопываются)

// Строка из данных — данные, а не код
Collection::make(['system', 'exec'])->contains('system'); // true — просто поиск значения

Возможности

  • Созданиеmake/wrap из массива, Traversable, Arrayable, скаляра или null; генерация times/range; fromJson с fail-safe-валидацией и лимитом глубины.
  • Доступ и поискfirst/last/get с default и предикатом, firstOrFail/sole с контрактными исключениями, firstWhere, строгий search.
  • Проверкиhas/hasAny, строгие contains/containsStrict/doesntContain, every/some, isEmpty/isNotEmpty.
  • Трансформацияmap/mapWithKeys/flatMap/pluck/keys/values/flip/ collapse/flatten/pad/reverse/shuffle.
  • Фильтрацияfilter/reject, всё where-семейство (where/whereIn/whereBetween/ whereNull/whereInstanceOf…), типобезопасные unique/duplicates, only/except.
  • Срезы и разбиениеslice/take*/skip*/nth/chunk/split/partition/ groupBy/keyBy/countBy.
  • Объединениеmerge/mergeRecursive/combine/union/concat/zip/crossJoin, строгие diff*/intersect*.
  • Агрегацияreduce/sum/avg/min/max/median/mode/implode/join; числовые строки считаются без потери типа и точности.
  • Сортировкаsort/sortDesc/sortBy/sortByDesc/sortKeys* (sortBy — по Шварцу: ключ вычисляется один раз на элемент).
  • Мутаторыpush/put/pull/forget/prepend/pop/shift/splice.
  • Higher-ordereach/tap/pipe/when/unless/whenEmpty/whenNotEmpty.
  • ИнтеграцияArrayAccess, Countable, IteratorAggregate, JsonSerializable, собственные контракты Arrayable/Jsonable; класс открыт для наследования (protected-хелперы — зафиксированный тестами контракт).

Функционально пакет покрывает возможности четырёх сравниваемых аналогов вместе взятых: illuminate/collections, doctrine/collections, ramsey/collection, aimeos/map.

Безопасность как дифференциатор

  • Строгие сравнения (===) по умолчанию во всех операциях поиска и сравнения: contains/search/where*/diff/intersect/unique. Классические ловушки type juggling (0 == 'admin', '0e123' == '0e456') исключены по построению.
  • Строка из данных никогда не вызывается как код: contains('system') — это поиск значения, а groupBy('trim') — извлечение поля trim, не вызов функции.
  • Строковый callable получает только значение: map('intval') не передаёт ключ вторым аргументом (у intval это база системы счисления — ловушка аналогов), filter('is_int') не падает ArgumentCountError.
  • Сериализация через cloudcastle/serialize: toSerialized/fromSerialized — JSON/PHP/igbinary/подписанный форматы с fail-safe контрактом, DoS-лимитами и анти-POP защитой (белый список классов).
  • JSON fail-safe: toJson() бросает исключение вместо тихого false; fromJson() проверяет корректность, тип верхнего уровня и клэмпит глубину.

Возможности против аналогов

Сводная таблица (генерируется автоматически из tools/features-data.php; значения выверены по коду и документации аналогов). Легенда: ✅ полностью · ⚠️ частично · 🔌 адаптер · ❌ нет · — неприменимо.

Сгенерировано из tools/features-data.php (факты о поддержке). Легенда: ✅ полностью · ⚠️ частично · 🔌 адаптер · ❌ нет · — неприменимо.

Создание

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
make / wrap из любых источников (iterable, Arrayable, скаляр, null) ⚠️ ⚠️ Паритет
times / range (генерация) Паритет
fromJson с fail-safe валидацией (исключение, лимит глубины) ⚠️ Collection

Доступ и поиск

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
first / last / get с default и предикатом ⚠️ ⚠️ Паритет
firstOrFail / sole (контрактные исключения) ⚠️ Collection, illuminate
search строгий по умолчанию ⚠️ ⚠️ Collection

Трансформация и фильтрация

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
map / mapWithKeys / flatMap / pluck ⚠️ ⚠️ Паритет
where-семейство (In / Between / Null / InstanceOf) ⚠️ ⚠️ ⚠️ Collection, illuminate
unique типобезопасный (1 ≠ '1' ≠ true) ⚠️ ⚠️ Collection
Строковый callable в map не получает ключ (нет ловушки intval) Collection

Агрегация и статистика

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
sum / avg / min / max по полю ⚠️ Паритет
median / mode ⚠️ Collection, illuminate
Числовые строки без потери типа и точности ⚠️ ⚠️ Collection

Группировка и разбиение

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
groupBy / keyBy / countBy ⚠️ Паритет
chunk / split / partition (вложенные коллекции) ⚠️ ⚠️ Collection, illuminate

Объединение множеств

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
merge / union / combine / concat / zip / crossJoin ⚠️ Паритет
diff / intersect со строгим сравнением ⚠️ ⚠️ ⚠️ Collection

Безопасность

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
Строгие сравнения по умолчанию (анти type juggling) ⚠️ ⚠️ ⚠️ Collection
Строка из данных никогда не вызывается как функция ⚠️ ⚠️ Collection
toJson бросает исключение вместо тихого false ⚠️ ⚠️ Collection
Zero runtime-зависимостей ⚠️ ⚠️ Collection, aimeos

Производительность

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
C-fast-path для замыканий без ключа (map / filter / reduce) ⚠️ Collection
array_column-путь для pluck / sum по полю Collection, ramsey, aimeos
Schwartzian-сортировка sortBy (n вызовов вместо n·log n) Collection, illuminate

Нагрузка и стабильность

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
Нагрузочные тесты в CI (100k элементов, бюджет памяти) Collection
Перф-бюджеты всех групп методов в CI Collection
Мутационное тестирование (MSI 100%) Collection

Расширяемость

Функция Collection illuminate doctrine ramsey aimeos 🏆 Победитель
Наследование с protected-хелперами (контракт зафиксирован тестами) ⚠️ ⚠️ ⚠️ Collection, ramsey
ArrayAccess + Countable + IteratorAggregate + JsonSerializable ⚠️ ⚠️ Паритет

Производительность

Изолированные замеры без Xdebug (composer compare), эквивалентные операции над одинаковыми данными. Метрика — ops/sec (больше — лучше); «—» — операция не поддерживается.

Сгенерировано из composer compare (PHP 8.1.34). Правки в блоке будут перезаписаны.

Сценарий cloudcastle/collection illuminate/collections doctrine/collections ramsey/collection aimeos/map loophp/collection 🏆 Победитель
Создание из массива (100 эл.) 10485760 ops/s 7741425 ops/s 10776732 ops/s 58189 ops/s 7309697 ops/s 162882 ops/s doctrine/collections
map (×100) 217592 ops/s 149494 ops/s 229928 ops/s 26438 ops/s 147828 ops/s 51155 ops/s doctrine/collections
filter (×100) 144179 ops/s 124079 ops/s 124960 ops/s 42030 ops/s 121987 ops/s 15715 ops/s cloudcastle/collection
where поле=значение (×100 структур) 87912 ops/s 11315 ops/s 31897 ops/s 42288 ops/s cloudcastle/collection
pluck поля из структур (×100) 1220339 ops/s 40254 ops/s 41788 ops/s 889830 ops/s cloudcastle/collection
groupBy полю (×100 структур) 75158 ops/s 18844 ops/s 69605 ops/s cloudcastle/collection
sum по полю (×100 структур) 329316 ops/s 25386 ops/s 223732 ops/s cloudcastle/collection
sortBy полю (×100 структур) 66873 ops/s 27390 ops/s 33674 ops/s cloudcastle/collection
unique (×100) 321772 ops/s 317399 ops/s 297937 ops/s cloudcastle/collection
contains строгий (×100) 4930995 ops/s 2927348 ops/s 5092647 ops/s 59065 ops/s 2955400 ops/s 8104 ops/s doctrine/collections
merge двух наборов (100 + 100) 1583832 ops/s 1468902 ops/s 17919 ops/s 1465003 ops/s cloudcastle/collection
chunk по 10 (×100) 474877 ops/s 431406 ops/s 304359 ops/s cloudcastle/collection
first по предикату (×100) 215899 ops/s 208100 ops/s 133213 ops/s 201102 ops/s 15780 ops/s cloudcastle/collection
reduce суммой (×100) 204616 ops/s 102043 ops/s 207366 ops/s 45738 ops/s 200650 ops/s 36209 ops/s doctrine/collections
JSON-цикл (encode + decode, ×100) 142195 ops/s 93062 ops/s 152560 ops/s aimeos/map

В микросценариях создание/map/contains/reduce doctrine опережает на 1–4%: его API опускает декларации возвращаемых типов (нет opcode-проверки на каждом вызове) и не передаёт ключи в callback. Мы сознательно сохраняем полную строгую типизацию и key-aware map. loophp — ленивые коллекции: в сценариях с материализацией это честно отражено вызовом all().

Полное сравнение по каждой возможности — в Wiki: Сравнение.

Заключение: когда что выбирать

Сильные стороны cloudcastle/collection — строгая семантика сравнений как встроенная защита от type juggling, суперсет API четырёх библиотек, ноль runtime-зависимостей и production-обвязка (100 % покрытие пятью видами тестов, Infection MSI 100 %, полный статанализ). Все выборки по полю (where/pluck/groupBy/sum/sortBy) — быстрейшие среди аналогов за счёт array_column-путей и сортировки по Шварцу.

Производительность: победитель в большинстве сценариев таблицы выше (см. графу «🏆 Победитель»): where — в ~7× быстрее illuminate, pluck — в ~29×, groupBy — в ~4×, sum по полю — в ~12×, sortBy — в ~2.4×. Замыкания без параметра ключа уходят в C-реализации array_map/array_filter/array_reduce (кэш арности на WeakMap).

Честные слабые стороны — там, где аналог выигрывает, причина семантическая, и мы осознанно платим за неё:

  • map/reduce/contains у doctrine/collections быстрее на ~3–5 %: он не поддерживает callback с ключом и не проверяет арность;
  • unique у illuminate быстрее на ~15 %: его array_unique нестрогий и схлопнул бы 1, '1' и true в одно значение;
  • chunk у aimeos/map быстрее в ~2×: его чанки — сырые массивы, наши — полноценные вложенные коллекции;
  • JSON-цикл у aimeos быстрее на ~8 %: без валидации типа верхнего уровня и клэмпа глубины.

Честные рекомендации:

  • Строгая семантика, финтех, работа с недоверенными даннымиcloudcastle/collection.
  • Экосистема Laravel целикомilluminate/collections (нативен для Laravel).
  • Типизированные DDD-коллекции сущностейramsey/collection или doctrine/collections (Criteria-запросы к ORM).
  • Максимальный перф на сырых массивах без обёртокaimeos/map или нативные array_*.

Документация

Качество

Пакет придерживается production-стандартов: строгая типизация, полный статический анализ (PHPStan max, Psalm level 1, PHPMD, Deptrac, Rector), покрытие тестами 100 % на каждый файл и мутационное тестирование (Infection MSI 100 %). Матрица CI — PHP 8.1–8.5.

composer ci        # полный пайплайн качества
composer check     # быстрые проверки перед коммитом
composer test      # тесты (unit + integration + security + load)
composer compare   # сравнение производительности с аналогами

Контакты

Поддержать проект

Реквизиты для поддержки автора — в DONATE.md.

Contributors

Спасибо всем, кто вносит вклад в проект:

Список ведётся по спецификации all-contributors.

Лицензия

MIT © CloudCastle