PHPackages                             eboreum/collections - 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. eboreum/collections

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

eboreum/collections
===================

Wish you had generics in PHP? This library provides a sensible means of managing collections of data (i.e. arrays with restrictions), immutably, until such a time that PHP generics are bestowed upon us.

2.0.0(1y ago)06.3k↑36%MITPHPPHP ^8.3CI passing

Since Apr 22Pushed 1y ago1 watchersCompare

[ Source](https://github.com/eboreum/collections)[ Packagist](https://packagist.org/packages/eboreum/collections)[ RSS](/packages/eboreum-collections/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (3)Dependencies (7)Versions (5)Used By (0)

Eboreum/Collections: Moving PHP closer towards generics
=======================================================

[](#eboreumcollections-moving-php-closer-towards-generics)

[![license](https://camo.githubusercontent.com/341ac5c049024acfd4874b76a0470ca26afb17d5715dd8d246edc3c2c70da89f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f65626f7265756d2f636f6c6c656374696f6e732e737667)](https://camo.githubusercontent.com/341ac5c049024acfd4874b76a0470ca26afb17d5715dd8d246edc3c2c70da89f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f65626f7265756d2f636f6c6c656374696f6e732e737667)[![build](https://github.com/eboreum/collections/workflows/build/badge.svg?branch=main)](https://github.com/eboreum/collections/workflows/build/badge.svg?branch=main)[![Code Coverage](https://camo.githubusercontent.com/03b6cec14618e7d107823c8b6bad880677e5d7371f73f033cbea354bbce5eaba/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f75726c3d68747470733a2f2f676973742e67697468756275736572636f6e74656e742e636f6d2f6b61666f736f2f34313732366636306635623631656233313937343539633166626665613930652f7261772f746573742d636f7665726167655f5f6d61696e2e6a736f6e)](https://github.com/eboreum/collections/actions)[![PHPStan Level](https://camo.githubusercontent.com/65707775dae14ad2b0b1ecfa9c8d95efe51b17b8771a1dc7069730f72ac34ce0/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f75726c3d68747470733a2f2f676973742e67697468756275736572636f6e74656e742e636f6d2f6b61666f736f2f34313732366636306635623631656233313937343539633166626665613930652f7261772f7068707374616e2d6c6576656c5f5f6d61696e2e6a736f6e)](https://github.com/eboreum/collections/actions)

Wish you had generics in PHP? This library provides a sensible means of managing collections of data (i.e. arrays with restrictions), immutably, until such a time that PHP generics are bestowed upon us.

Comes fully equipped with [phpstan](https://packagist.org/packages/phpstan/phpstan) generics annotations. For details, see:

The main goals of this library are:

1. **Accuracy**.
    - You know with certainty what the collections in your code base can and must contain.
2. **Safety**.
    - Immutability prevents unintentional modifications of collections.
    - You get an exception as soon as an invalid element is encountered.

It is ***not*** intended for speed. If you need speed in certain areas, you still have e.g. raw array manipulation you can rely on.

Requirements
============

[](#requirements)

```
"php": "^8.3",
"eboreum/caster": "^2.1",
"eboreum/exceptional": "^2.0"
```

For more information, see the [`composer.json`](composer.json) file.

Installation
============

[](#installation)

Via [Composer](https://getcomposer.org/) ():

```
composer install eboreum/collections

```

Via GitHub:

```
git clone git@github.com:eboreum/collections.git

```

Fundamentals
============

[](#fundamentals)

This library has two core components:

1. The class `Eboreum\Collections\Collection`.
2. The interface `Eboreum\Collections\Contract\CollectionInterface`.

`Eboreum\Collections\Collection` by itself imposes no restrictions and may used for storing any data type. It can be thought of as a fancy array. However, it has two crucial differences and advantages over simple arrays: It's **immutable** and it's **type hinted**, including annotations for generics ().

The true power of this library shows once you start making collection classes, extending `Eboreum\Collections\Collection`, which have restrictions.

This library comes equipped with the following simple data type collection classes:

- `Eboreum\Collections\FloatCollection`: A collection, which only ever contains float numbers.
- `Eboreum\Collections\IntegerCollection`: A collection, which only ever contains integers.
- `Eboreum\Collections\ObjectCollection`: A collection, which only ever contains objects – any objects. More on how to make collections for specific class instances below.
- `Eboreum\Collections\StringCollection`: A collection, which only ever contains strings.

The real shine comes when we start making restrictions on the contents of the collection classes, for instance **restrictions on specific classes**.

This library has the following **predefined class collections**, all located under the namespace `\Eboreum\Collections\Object_`:

- `ClosureCollection`: A collection, which may and will only ever contain instances of `\Closure`.
- `DateTimeCollection`: A collection, which may and will only ever contain instances of `\DateTime`.
- `DateTimeImmutableCollection`: A collection, which may and will only ever contain instances of `\DateTimeImmutable`.
- `DateTimeInterfaceCollection`: A collection, which may and will only ever contain instances of `\DateTimeInterface`.
- `DirectoryCollection`: A collection, which may and will only ever contain instances of `\Directory`.
- `ErrorCollection`: A collection, which may and will only ever contain instances of `\Error`.
- `ExceptionCollection`: A collection, which may and will only ever contain instances of `\Exception`.
- `SplFileInfoCollection`: A collection, which may and will only ever contain instances of `\SplFileInfo`.
- `SplFileObjectCollection`: A collection, which may and will only ever contain instances of `\SplFileObject`.
- `ThrowableCollection`: A collection, which may and will only ever contain instances of `\Throwable`.
- `stdClassCollection`: A collection, which may and will only ever contain instances of `\stdClass`.

You may use the above files as inspiration on how to build your own specific class collections.

The above classes utilize the abstract class `\Eboreum\Collections\Abstraction\AbstractNamedClassOrInterfaceCollection` and subsequently the interface `\Eboreum\Collections\Contract\ObjectCollectionInterface`.

Make collections for anything – not just classes
------------------------------------------------

[](#make-collections-for-anything--not-just-classes)

You may make restrictions for anything – not just classes – including unions (). Essentially, you merely have to override the `isElementAccepted` method in the collection class you are implementing.

Need something that will accept both integers and float numbers (a union)?

Simply do the following:

```
/**
 * {@inheritDoc}
 */
public static function isElementAccepted($element): bool
{
    return is_int($element) || is_float($element);
}
```

Do remember: If you utilize phpstan, you should also add and/or update the `@template` and its references throughout your custom collection class.

You should also override methods such as `current`, `find`, `first`, etc. with a suitable return type. For instance:

PHP ^8.1:

```
/**
 * {@inheritDoc}
 */
public function current(): int|float
{
    // ...
}
```

Notice: Intersection types () are **not supported** as they are not supported by PHP 8 due to [https://wiki.php.net/rfc/nullable\_intersection\_types](https://wiki.php.net/rfc/nullable_intersection_types) having been declined.

The reason is that methods such as `current`, `find`, `first`, etc. cannot have nullable return types when handling intersections.

Why is immutability necessary?
==============================

[](#why-is-immutability-necessary)

Simply put: You unintentionally risk changing mutable ("non-immutable") objects when they are being passed around the code base. You and your team may know not to change a mutable object in code bases you control, but third-party libraries (e.g. via Composer) certainly will not respect your rules. Eventually, someone in your team ***will*** forget about your "do-not-change" rule and introduce an ugly bug, which often times is hard to track down.

Real-world example of a mutable object incident
-----------------------------------------------

[](#real-world-example-of-a-mutable-object-incident)

Imagine you have a database ORM (Doctrine, Eloquent, etc.). If you use `DateTime` instead of `DateTimeImmutable`, passing that instance of `DateTime` around may change it. Consider this: The instance of `DateTime` was used to set an end date from which point a user can no longer log in to your application. The same instance of `DateTime` was used across 100 users (e.g. for optimization reasons). Now your code, because of the change on the `DateTime` instance, inadvertently blocked 100 users from using your application. Such a type of bug is ***very*** hard to find the root cause for.

Tests
=====

[](#tests)

Test/development requirements
-----------------------------

[](#testdevelopment-requirements)

```
"phpstan/phpstan": "^2.1.5",
"phpunit/phpunit": "^12.1",
"slevomat/coding-standard": "8.15.0",
"squizlabs/php_codesniffer": "3.12.2",
"symfony/polyfill-intl-icu": "^1.31"
```

Running tests
-------------

[](#running-tests)

For all unit tests, first follow these steps:

```
cd tests
php ../vendor/bin/phpunit

```

License &amp; Disclaimer
========================

[](#license--disclaimer)

See [`LICENSE`](LICENSE) file. Basically: Use this library at your own risk.

Contributing
============

[](#contributing)

We prefer that you create a ticket and or a pull request at , and have a discussion about a feature or bug here.

Version branches
----------------

[](#version-branches)

- `2.x` = `main`
- `1.x`

No `\ArrayAccess`!
------------------

[](#no-arrayaccess)

This library does not and will not utilize `\ArrayAccess` ().

It goes against the immutable nature of this library, it's a little bit evil, and it makes code unnecessarily obscure.

Credits
=======

[](#credits)

Authors
-------

[](#authors)

- **Kasper Søfren** (kafoso)
    E-mail: [](mailto:soefritz@gmail.com)
    Homepage: [](https://github.com/kafoso)
- **Carsten Jørgensen** (corex)
    E-mail: [](mailto:dev@corex.dk)
    Homepage: [](https://github.com/corex)

Acknowledgements
----------------

[](#acknowledgements)

### doctrine/collections

[](#doctrinecollections)

This library is greatly inspired by  () and some of the code is indeed copied from that library (acknowledged by inclusion of the LICENSE file contents at the top of select files, as required by ).

Laravel collection
------------------

[](#laravel-collection)

For certain methods, we have also drawn inspiration from .

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance48

Moderate activity, may be stable

Popularity23

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 96.8% of commits — single point of failure

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

Every ~363 days

Total

4

Last Release

388d ago

Major Versions

1.x-dev → 2.0.02025-04-17

PHP version history (2 changes)1.0.0PHP ^8.1

2.0.0PHP ^8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/83704139?v=4)[Eboreum](/maintainers/eboreum)[@eboreum](https://github.com/eboreum)

---

Top Contributors

[![kafoso](https://avatars.githubusercontent.com/u/3169691?v=4)](https://github.com/kafoso "kafoso (91 commits)")[![corex](https://avatars.githubusercontent.com/u/21259173?v=4)](https://github.com/corex "corex (3 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/eboreum-collections/health.svg)

```
[![Health](https://phpackages.com/badges/eboreum-collections/health.svg)](https://phpackages.com/packages/eboreum-collections)
```

###  Alternatives

[phmlabs/annovent

Simple lightweight event dispatcher using annotations for registering listeners

113.3k](/packages/phmlabs-annovent)

PHPackages © 2026

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