Search by

oceanmoon / collections

mossy2100

Type-safe PHP collections: Sequence (ordered list), Dictionary (any-type keys), Set (unique values), with runtime type validation.

Package info

github.com/mossy2100/PHP-Collections

pkg:composer/oceanmoon/collections

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v2.0.0 2026-06-18 00:10 UTC

This package is auto-updated.

Last update: 2026-10-27 10:42:04 UTC


README

Type-safe collection classes for PHP 8.4+.

License | Changelog | Documentation

PHP 8.4

Description

A type-safe collection library featuring runtime type validation, immutable operations, and unrestricted key types.

Core Classes:

  • Sequence - Ordered lists with integer indexing
  • Dictionary - Key-value pairs accepting any type as keys
  • Set - Unique value collections with set operations

Development and Quality Assurance

This package was developed with Claude Code:

  • The author developed the initial concept, designed the public API, and did most of the initial coding.
  • Claude Code wrote the tests and most of the documentation.
  • Claude Code also assisted with multiple code reviews, which led to bug fixes, performance improvements and other refinements.

The code is checked with:

Code Coverage

Why these collections?

PHP's native arrays are powerful but have limitations:

  • Keys restricted to strings and integers - Can't use booleans, floats, arrays, or objects as keys.
  • No type safety - Arrays accept any mix of types without validation.
  • Type coercion issues - Keys like 1, '1', true, and 1.0 all become the same key.
  • Limited operations - Built-in array functions lack chaining, immutability, and advanced transformations. Errors and exceptions are inconsistent.

The collection classes in this package solve these problems with:

✅ Any type as keys - Use objects, arrays, booleans, floats, null as Dictionary keys.

✅ Runtime type validation - Optional type constraints with compile-time-like checking.

✅ Rich API - Fluent interfaces, method chaining, functional programming support.

✅ Immutable operations - Transformations return new collections without modifying originals.

✅ Type inference - Automatically detect types from your data.

✅ Mathematical correctness - Proper type safety for operations like sum() and product().

Alternatives

Before using this package, you may want to check out these PHP extensions:

These are official PHP extensions that provide efficient data structure implementations and will probably be well-supported going forward. However, if you need runtime type safety and generics-like behavior, or simply prefer a more functional style of programming, the collection classes in this package provides features that these extensions lack, including type constraints, type inference, and type-safe operations.

Features

Type Safety

// Restrict types at runtime
$numbers = new Sequence('int');
$numbers->append(1, 2, 3);    // ✅ Works
$numbers->append('four');      // ❌ InvalidArgumentException

// Union types
$mixed = new Sequence('int|string');
$mixed->append(1, 'two', 3);   // ✅ All work

// Type inference
$seq = new Sequence(source: [1, 2, 3]);
// Automatically infers type as 'int'

Unrestricted Keys

// PHP arrays: keys must be string|int
$array = [];
$array[new DateTime()] = 'event';  // ❌ TypeError: Cannot access offset of type DateTime on array
$array[[1, 2]] = 'coords';         // ❌ TypeError: Cannot access offset of type array on array

// Dictionary: any type works
$dict = new Dictionary();
$dict[new DateTime()] = 'event';         // ✅ Works
$dict[[1, 2, 3]] = 'coordinates';        // ✅ Works
$dict[fopen('file.txt', 'r')] = 'data';  // ✅ Works
$dict[true] = 'yes';                     // ✅ Works
$dict[null] = 'empty';                   // ✅ Works

Functional Programming

$numbers = new Sequence('int', source: [1, 2, 3, 4, 5]);

// Method chaining
$result = $numbers
    ->filter(fn($n) => $n % 2 === 0)  // Keep evens
    ->map(fn($n) => $n * 2)            // Double them
    ->reverse();                       // Reverse order

echo $result; // [8, 4]

// Original unchanged (immutable operations)
echo $numbers; // [1, 2, 3, 4, 5]

Set Operations

$set1 = new Set('int', [1, 2, 3, 4]);
$set2 = new Set('int', [3, 4, 5, 6]);

$union = $set1->union($set2);           // {1, 2, 3, 4, 5, 6}
$intersection = $set1->intersect($set2); // {3, 4}
$difference = $set1->diff($set2);        // {1, 2}

// Subset checking
$set1->subset($set2);      // false
$set1->disjoint($set2);  // false

Installation

composer require mossy2100/collections

Requirements

  • PHP ^8.4
  • mossy2100/core

Quick Start

Sequence - Type-safe lists

use Mossy2100\Collections\Sequence;

// Create with type inference
$seq = new Sequence(source: [1, 2, 3, 4, 5]);

// Add items
$seq->append(6, 7, 8);
$seq->prepend(0);

// Remove items
$item = $seq->removeByIndex(0);  // 0 (the removed value)
$count = $seq->removeByValue(8); // 1 (the number of items removed)

// Access items
echo $seq[0];        // 1
echo $seq->first();  // 1
echo $seq->last();   // 7

// Transformations
$evens = $seq->filter(fn($n) => $n % 2 === 0);
$doubled = $seq->map(fn($n) => $n * 2);
$sorted = $seq->sort();

// Aggregations
echo $seq->sum();      // 28
echo $seq->product();  // 5040
echo $seq->average();  // 4
echo $seq->min();      // 1
echo $seq->max();      // 7

Dictionary - Key-value pairs with any type

use Mossy2100\Collections\Dictionary;

// Create without type constraints, so keys and values can be any type
$dict = new Dictionary(null, null, ['a' => 1, 'b' => 2]);

// Use objects as keys
$dict[new DateTime('2024-01-01')] = 'New Year';

// Use arrays as keys
$dict[[10, 20]] = 'coordinates';

// Type constraints
$typed = new Dictionary('string', 'int');
$typed['count'] = 42;      // ✅ Works
$typed['count'] = 'text';  // ❌ InvalidArgumentException

// Check and access
if ($dict->keyExists('a')) {
    echo $dict['a'];  // 1
}

// Iteration
foreach ($typed as $key => $value) {
    echo "$key => $value\n"; // count => 42
}

Set - Unique values

use Mossy2100\Collections\Set;

// Duplicates automatically removed
$set = new Set(source: [1, 2, 2, 3, 3, 3]);
echo $set->count(); // 3

// Set operations
$a = new Set('int', [1, 2, 3]);
$b = new Set('int', [2, 3, 4]);

$a->union($b);       // {1, 2, 3, 4}
$a->intersect($b);   // {2, 3}
$a->diff($b);        // {1}

// Membership testing
var_dump($set->contains(2));  // true
var_dump($set->contains(5));  // false

Classes

Core Collections

  • Collection - Abstract base class providing shared functionality for all collection types
  • Sequence - Ordered lists with integer indexing, similar to List<T> in C# or Java
  • Dictionary - Key-value pairs accepting any PHP type for both keys and values
  • Set - Unique value collections with mathematical set operations

Supporting Classes

  • TypeSet - Runtime type validation and constraint management
  • Pair - Immutable key-value pair container

Testing

The library includes comprehensive test coverage:

# Run all tests
vendor/bin/phpunit

# Run all tests for a specific collection type
vendor/bin/phpunit tests/Dictionary

# Run specific test class
vendor/bin/phpunit tests/Sequence/SequenceTransformationTest.php

# Run with coverage (generates HTML report and clover.xml)
composer test

Test Coverage:

  • 600+ tests across all classes
  • 100% code coverage
  • Edge cases, error conditions, and type safety

License

MIT License - see LICENSE for details

Support

For questions or suggestions, please open an issue.

Changelog

See CHANGELOG.md for version history and changes.