php-standard-library/collection
Generic, object-oriented Vector, Map, and Set collections for PHP with both immutable and mutable variants. Part of PHP Standard Library; designed for a consistent, type-friendly API. Full docs at php-standard-library.dev.
Installation:
composer require php-standard-library/collection
Add to composer.json under require:
"php-standard-library/collection": "^6.0"
First Use Case: Replace a simple array operation with a typed, immutable collection:
use PHPStandardLibrary\Collection\Vector;
// Before: Mutable array
$numbers = [1, 2, 3];
$doubled = array_map(fn($n) => $n * 2, $numbers);
// After: Immutable Vector
$immutableDoubled = Vector::of(1, 2, 3)->map(fn(int $n): int => $n * 2);
Where to Look First:
src/Collection/ directory in the package for source code (e.g., Vector.php, Map.php).Vector for lists, Map for key-value pairs, and Set for unique collections.Immutable Workflows:
// Safe for concurrent access (e.g., caching, jobs)
$users = Vector::of(User::all())
->filter(fn(User $u) => $u->isActive())
->map(fn(User $u) => $u->name)
->freeze(); // Immutable!
Mutable Performance Optimizations:
// In-place updates for high-throughput operations
$mutableVector = Vector::mutableOf(1, 2, 3);
$mutableVector->push(4); // No new object created
Type-Safe Collections:
// Strong typing for domain models
use PHPStandardLibrary\Collection\Map;
/** @var Map<string, User> */
$userMap = Map::of(['id1' => $user1, 'id2' => $user2]);
$user = $userMap->get('id1'); // Returns User|null
Laravel Integration:
// Wrap Eloquent results
$users = User::all()->mapInto(Vector::class);
// Convert back to Laravel Collection
$laravelCollection = $vector->toLaravelCollection();
Functional Chaining:
// Replace nested array functions
$result = Vector::of($orders)
->filter(fn(Order $o) => $o->total > 100)
->map(fn(Order $o) => $o->customerId)
->unique()
->sort();
Data Transformation Pipeline:
$processedData = Vector::of($rawData)
->map(fn($item) => (object) $item) // Normalize
->filter(fn(object $o) => $o->valid) // Validate
->groupBy(fn(object $o) => $o->category) // Group
->mapValues(fn(Vector $group) => $group->sum('value')); // Aggregate
State Management in Jobs:
// Thread-safe job state
$jobState = Vector::of($initialState)->freeze();
// ...
$updatedState = $jobState->map(fn($item) => $item->process());
Testing with Immutable Snapshots:
// Reproducible test data
$testData = Vector::of(1, 2, 3)->freeze();
$this->assertEquals($testData, $testData->map(fn($n) => $n * 2));
Hybrid with Laravel Collections:
// Convert Laravel Collection to Vector
$vector = Laravel\Collection::make([1, 2, 3])->mapInto(Vector::class);
// Convert back
$laravelCollection = $vector->toLaravelCollection();
Custom Value Objects:
// Use with DTOs or value objects
$orders = Vector::of(Order::class, $orderData);
Performance-Critical Paths:
Vector::mutableOf() for bulk operations (e.g., batch processing).Set for deduplication (e.g., Set::of($items)->toArray()).API Responses:
// Type-safe API responses
return response()->json(
Vector::of($users)
->map(fn(User $u) => ['id' => $u->id, 'name' => $u->name])
->toArray()
);
Immutable Overhead:
// Bad: Creates N new objects
$result = Vector::of([...]);
for ($i = 0; $i < 1000; $i++) {
$result = $result->map(...); // Expensive!
}
Type Safety Strictness:
// Fails: Inconsistent types
$mixed = Vector::of(1, 'two', 3.0); // Error if strict typing is enabled
Vector::ofAny() (if available).Laravel Collection Incompatibilities:
pluck() or groupBy() may not exist. Use functional equivalents:
// Laravel: $collection->pluck('name')
// Standard Library: $vector->map(fn($item) => $item->name)
Serialization Quirks:
// May fail in Redis or database
Cache::put('key', $immutableVector->freeze());
$immutableVector->toArray().Circular References:
User with orders containing User) may cause infinite loops:
$user->orders->map(fn(Order $o) => $o->user); // Risk of recursion
->toArray() for serialization or implement __serialize().Unexpected Mutations:
push() on an immutable Vector).Collection macros overriding behavior.Type Errors:
php.ini (strict_types=1) to catch issues early.phpstan or psalm for static analysis:
vendor/bin/phpstan analyse --level=max src/
Performance Bottlenecks:
xdebug or blackfire.io to identify expensive operations (e.g., map on large immutable collections).Autoloading:
composer dump-autoload is run after installation to avoid ClassNotFound errors.Laravel Service Provider:
Collection, bind the package in AppServiceProvider:
use PHPStandardLibrary\Collection\Vector;
public function register()
{
Laravel\Collection::macro('toVector', function () {
return Vector::of($this->all());
});
}
Custom Collections:
class UserVector extends Vector
{
public function activeOnly(): self
{
return $this->filter(fn(User $u) => $u->isActive());
}
}
Laravel Macros:
Collection:
Laravel\Collection::macro('toImmutableVector', function () {
return Vector::of($this->all())->freeze();
});
Interoperability:
ArrayAccess or IteratorAggregate for seamless integration with Laravel’s utilities:
$vector->getIterator(); // Works with Laravel's collection helpers
Testing Helpers:
$this->assertVectorEquals(
Vector::of(1, 2, 3),
Vector::of(1, 2, 3)->map(fn($n) => $n)
);
freeze() for function arguments to enforce immutability:
How can I help you explore Laravel packages today?