PHPackages                             purrphp/pure-collection - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. purrphp/pure-collection

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

purrphp/pure-collection
=======================

Immutable type-safe collections for PHP

1.0.0(1mo ago)06↑2900%1MITPHPPHP ^8.1CI passing

Since Mar 27Pushed 1mo agoCompare

[ Source](https://github.com/PurrPHP/pure-collection)[ Packagist](https://packagist.org/packages/purrphp/pure-collection)[ Docs](https://github.com/purrphp/collection)[ RSS](/packages/purrphp-pure-collection/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (3)Versions (2)Used By (1)

PurrPHP/collection
==================

[](#purrphpcollection)

Type-safe collections for PHP 8. Type safety based on native PHP features, not static analyzers. Inspired by [Kotlin collections](https://kotlinlang.org/docs/collections-overview.html).

Documentation
-------------

[](#documentation)

- [Common Methods](docs/common-methods.md) — methods available on every collection
- [Int Collections](docs/int-collections.md) — integer-typed classes and their specific API
- [String Collections](docs/string-collections.md) — string-typed classes and their specific API
- [Custom Collections](docs/custom-collections.md) — step-by-step guide for implementing your own typed collection
- [Architecture Decisions](docs/adr.md) — key design decisions and their rationale

### Problem scope

[](#problem-scope)

PHP has no native typed collections — only plain arrays. This makes it easy to accidentally mix types or corrupt key structure:

```
$uuids = [];
$uuids[] = Uuid::fromInteger('1');
$uuids[] = '00000000-0000-0000-0000-000000000001'; // wrong type, no error

$uuids[] = Uuid::fromInteger('2');
$uuids['validUuid'] = Uuid::fromInteger('3');       // mixed int/string keys
```

This library solves these problems by providing type-safe, semantically clear collections that reduce boilerplate and prevent mistakes at runtime.

Code structure
--------------

[](#code-structure)

Inspired by [Kotlin collections](https://kotlinlang.org/docs/collections-overview.html), the library provides three collection types:

- **List** — ordered sequence with integer keys, duplicates allowed
- **Set** — ordered sequence of unique values
- **Map** — associative array (key → value)

Each type has an **immutable** (default) and a **mutable** variant (except set). Immutable methods return a new instance; mutable methods modify the instance in place and return `$this`.

Hierarchy:

```
CollectionInterface
└── AbstractCollection
    ├── AbstractList               — ordered list (sequential integer keys)
    │   ├── AbstractSet            — deduplicates values on construction
    │   └── AbstractMutableList    — ArrayAccess + in-place mutation
    └── AbstractMap                — associative map (string/int keys)
        └── AbstractMutableMap     — ArrayAccess + in-place mutation

```

Available Classes
-----------------

[](#available-classes)

ClassTypeDescription`IntList`Immutable listOrdered list of integers`IntSet`Immutable setOrdered list of unique integers`IntNotEmptyList`Immutable listSame as `IntList`, throws on empty construction`IntNotEmptySet`Immutable setSame as `IntSet`, throws on empty construction`IntMap`Immutable mapAssociative (key → int) map`IntMutableList`Mutable listOrdered list of integers, in-place mutation`IntMutableMap`Mutable mapAssociative (key → int) map, in-place mutation`IntMutableSet`Mutable setOrdered list of unique integers, in-place mutation`StringList`Immutable listOrdered list of strings`StringSet`Immutable setOrdered list of unique strings`StringNotEmptySet`Immutable setSame as `StringSet`, throws on empty construction`StringMap`Immutable mapAssociative (key → string) map`StringMutableMap`Mutable mapAssociative (key → string) map, in-place mutationInstallation
------------

[](#installation)

```
composer require purrphp/pure-collection
```

Usage
-----

[](#usage)

### Lists

[](#lists)

```
use Purr\Collection\IntList;

$numbers = new IntList(1, 2, 3, 4, 5);

$even    = $numbers->filter(fn(int $n): bool => $n % 2 === 0);
$doubled = $numbers->map(fn(int $n): int => $n * 2); // returns array
$sum     = $numbers->reduce(fn(int $carry, int $n): int => $carry + $n, 0);
$sorted  = $numbers->sorted(fn(int $a, int $b): int => $b  $a);

$numbers->count();      // 5
$numbers->isEmpty();    // false
$numbers->isNotEmpty(); // true
$numbers->max();        // 5
$numbers->min();        // 1
```

### Sets (unique values)

[](#sets-unique-values)

```
use Purr\Collection\IntSet;
use Purr\Collection\StringSet;

$set = new IntSet(1, 2, 3, 2, 1); // duplicates are removed
$set->toArray();                   // [1, 2, 3]

$ids = IntSet::fromString('1,2,3', separator: ',');
$ids->join(',');                   // "1,2,3"

$tags = new StringSet('php', 'oop', 'php');
$tags->toArray();                  // ['php', 'oop']
$tags->sortedAlphabetically()->toArray(); // ['oop', 'php']

$a = new StringSet('a', 'b', 'c');
$b = new StringSet('b', 'c', 'd');
$a->diff($b)->toArray();           // ['a']
```

### Maps

[](#maps)

```
use Purr\Collection\IntMap;

$map = new IntMap(...['a' => 1, 'b' => 2, 'c' => 3]);

$map->filter(fn(int $v): bool => $v > 1)->toArray(); // ['b' => 2, 'c' => 3]
$map->groupBy(fn(int $v): string => $v % 2 === 0 ? 'even' : 'odd');
```

### Mutable collections

[](#mutable-collections)

Mutable collections modify their internal state in place and support `ArrayAccess`:

```
use Purr\Collection\IntMutableList;
use Purr\Collection\IntMutableSet;
use Purr\Collection\StringMutableMap;

// IntMutableList — in-place mutation, fluent chaining
$list = new IntMutableList(3, 1, 2);
$list->sortAsc()   // [1, 2, 3]
     ->add(4, 5);  // [1, 2, 3, 4, 5]

$list[] = 6;       // ArrayAccess append  → [1, 2, 3, 4, 5, 6]
$list[0] = 10;     // replace by index    → [10, 2, 3, 4, 5, 6]
unset($list[0]);   // remove by index     → [2, 3, 4, 5, 6]

// IntMutableSet — same as IntMutableList but keeps values unique
$set = new IntMutableSet(1, 2, 3);
$set->add(3, 4); // duplicate 3 ignored  → [1, 2, 3, 4]

// StringMutableMap — associative map with ArrayAccess
$map = new StringMutableMap();
$map['env']    = 'prod';
$map['region'] = 'eu';
unset($map['env']);
$map->toArray(); // ['region' => 'eu']
```

### Common Operations

[](#common-operations)

All collections implement `CollectionInterface`. See the full reference:

- [Common Methods](docs/common-methods.md) — searching, filtering, transforming, grouping, sizing, iteration
- [Int Collections](docs/int-collections.md) — aggregation, sorting, set operations, and mutable variants
- [String Collections](docs/string-collections.md) — alphabetical sorting, set operations, and mutable variants

Extending
---------

[](#extending)

To create a custom typed collection, extend `AbstractList`, `AbstractSet`, or `AbstractMap`. See [Architecture Decisions](docs/adr.md) for a full guide.

```
use Purr\Collection\AbstractSet;

/** @template-extends AbstractSet */
class DateSet extends AbstractSet
{
    public function __construct(\DateTimeImmutable ...$dates)
    {
        parent::__construct($dates);
    }

    protected function filterUniqValues(array $items): array
    {
        $result = [];

        foreach ($items as $item) {
            $result[$item->getTimestamp()]   = $item;
        }

        return $result;
    }
}
```

Development
-----------

[](#development)

```
composer install

composer test        # Run tests
composer analyse     # Static analysis
composer cs-check    # Code style check
composer cs-fix      # Fix code style
composer check       # All checks
```

### With Docker / Make

[](#with-docker--make)

```
make test       # Run tests
make analyse    # Static analysis
make cs-check   # Code style check
make check      # All checks
make shell      # Open shell in dev container
```

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance90

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community5

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

46d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5460215?v=4)[Aleksey M](/maintainers/don-tre)[@don-tre](https://github.com/don-tre)

---

Tags

phpmapsetcollectionlistimmutabledata structurestype-safe

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/purrphp-pure-collection/health.svg)

```
[![Health](https://phpackages.com/badges/purrphp-pure-collection/health.svg)](https://phpackages.com/packages/purrphp-pure-collection)
```

###  Alternatives

[phpcollection/phpcollection

General-Purpose Collection Library for PHP

1.0k64.0M34](/packages/phpcollection-phpcollection)[aimeos/map

Easy and elegant handling of PHP arrays as array-like collection objects similar to jQuery and Laravel Collections

4.2k412.9k11](/packages/aimeos-map)[chdemko/sorted-collections

Sorted Collections for PHP &gt;= 8.2

222.5M3](/packages/chdemko-sorted-collections)[equip/structure

Simple, immutable data structures

40201.9k2](/packages/equip-structure)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
