Getting Started
Installation
composer require noctud/collectionRequires PHP 8.4 or later.
Architecture
Three core types, each in mutable and immutable variants:
Collection<E> → Ordered elements, read-only
├── List<E> → Indexed, array access
│ ├── ImmutableList<E> → Mutation returns new
│ └── MutableList<E> → Mutation returns itself
└── Set<E> → Unique values, no array access
├── ImmutableSet<E> → Mutation returns new
└── MutableSet<E> → Mutation returns itself
Map<K,V> → Ordered key-value pairs, array access
├── ImmutableMap<K,V> → Mutation returns new
└── MutableMap<K,V> → Mutation returns itselfExtensible by design
Every node in this hierarchy is an interface, not a class. The library ships with default implementations backed by logic traits, but any library or application can provide its own implementation. See the Extending guide for details.
The API is heavily inspired by Kotlin Collections — factory functions, the mutable/immutable split, OrNull conventions, and method naming all follow Kotlin patterns.
The type hierarchy draws from the Java Collections Framework with clear separation of mutability/immutability.
Creating Collections
Use the factory functions from the Noctud\Collection namespace:
use function Noctud\Collection\listOf; // mutableListOf, setOf, ...Universal Immutable and Mutable collections:
$list = listOf([1, 2, 3]); // ImmutableList<int>
$set = setOf(['a', 'b', 'c']); // ImmutableSet<string>
$map = mapOf(['a' => 'b']); // ImmutableMap<string, string>$list = mutableListOf([1, 2, 3]); // MutableList<int>
$set = mutableSetOf(['a', 'b', 'c']); // MutableSet<string>
$map = mutableMapOf(['a' => 'b']); // MutableMap<string, string>Optimized string-keyed only Maps (int keys are only allowed when constructing from array)
$immutable = stringMapOf(['1' => 'a']); // ImmutableMap<string, string>
$mutable = mutableStringMapOf(['1' => 'a']); // MutableMap<string, string>Optimized int-keyed only Maps (keys must be int, even when constructing from array)
$immutable = intMapOf([1 => 'a']); // ImmutableMap<int, string>
$mutable = mutableIntMapOf([1 => 'a']); // MutableMap<int, string>Object keys? Use mapOfPairs
PHP arrays only support string|int keys, so mapOf() can't accept objects as keys. Use mapOfPairs() (or mutableMapOfPairs()) with [key, value] tuples instead:
$user = new User(1);
$map = mapOfPairs([[$user, 'admin']]); // ImmutableMap<User, string>
$map = mutableMapOfPairs([[$user, 'admin']]); // MutableMap<User, string>Accessing Elements
Array access is strict — it throws on missing keys/indices, just like get(). Use the ?? operator for safe fallback, or getOrNull() for the nullable variant:
$list[0]; // throws if index is out of bounds
$list[0] ?? null; // null if index is out of bounds
$list->getOrNull(0); // null if index is out of bounds
$map['key']; // throws if key is missing
$map['key'] ?? null; // null if key is missing
$map->getOrNull('key'); // null if key is missingSets do not support indexed access. Use contains() instead:
$set->contains('a'); // trueTransforming
Transformation methods (filter, map, sorted, etc.) always return immutable collections, regardless of whether the source is mutable or immutable. Chain them freely:
// [50, 40, 30]
$result = mutableListOf([1, 2, 3, 4, 5])
->filter(fn($n) => $n > 2) // ImmutableList
->map(fn($n) => $n * 10) // ImmutableList
->reversed(); // ImmutableListIterating
All collections are Traversable, there are 2 ways to iterate:
foreach ($map as $key => $value) {
echo "$key = $value\n";
}
// returns itself for chaining
$set->forEach(fn($el) => process($el));What's Next
- List guide — indexed sequences
- Set guide — unique element collections
- Map guide — key-value pairs with type-safe keys
- Mutability — mutable vs immutable patterns
- Lazy Initialization — deferred initialization
- Sorting — comprehensive sorting reference
- API Reference — complete method listing