php-standard-library/vec
php-standard-library/vec provides small, focused helpers for working with sequential 0-indexed arrays (lists). Create, map, filter, transform, and compose list operations with predictable behavior and clean APIs—part of the PHP Standard Library collection.
Installation:
composer require php-standard-library/vec
No additional configuration or service provider setup is required.
First Use Case:
Replace a simple array transformation with Vec for clarity and safety:
use PhpStandardLibrary\Vec;
// Raw array approach
$rawArray = [1, 2, 3, 4, 5];
$doubled = array_map(fn($n) => $n * 2, $rawArray);
$even = array_filter($doubled, fn($n) => $n % 2 === 0);
// Vec approach
$vec = Vec::fromArray([1, 2, 3, 4, 5]);
$result = $vec->map(fn($n) => $n * 2)->filter(fn($n) => $n % 2 === 0);
// Returns Vec([4, 8])
Where to Look First:
Vec::fromArray(), map(), filter(), reduce(), and toArray().Vec in service layers or DTOs where array logic is complex.Data Transformation Pipelines:
Use Vec to chain operations in a readable, functional style:
$users = Vec::fromArray(User::all()->toArray());
$activeAdmins = $users
->filter(fn($user) => $user['is_active'] && $user['role'] === 'admin')
->map(fn($user) => $user['email'])
->sort();
Immutable Collections:
Leverage Vec for operations where immutability is critical (e.g., caching intermediate results):
$baseVec = Vec::fromArray([1, 2, 3]);
$transformed = $baseVec->map(fn($n) => $n * 2); // Original $baseVec remains unchanged
Service Layer Abstractions: Encapsulate array logic in services for reusability:
class UserService {
public function getActiveAdmins(): Vec {
return Vec::fromArray(User::all()->toArray())
->filter(fn($user) => $user['is_active'])
->map(fn($user) => new AdminDto($user));
}
}
DTO Validation:
Use Vec to validate and transform input data:
$input = Vec::fromArray(request()->input('items'));
$validated = $input->map(fn($item) => (new ItemDto())->fill($item))
->filter(fn($item) => $item->isValid());
Integration with Laravel Collections:
Convert between Vec and Laravel Collection as needed:
$collection = collect([1, 2, 3]);
$vec = Vec::fromArray($collection->toArray());
$newCollection = Collection::make($vec->map(fn($n) => $n * 2)->toArray());
ETL Processes:
Use Vec for Extract-Transform-Load operations where clarity and safety are prioritized:
$data = Vec::fromArray($rawData)
->map(fn($row) => (new DataRow($row))->transform())
->filter(fn($row) => $row->isValid());
Batch Processing:
Process records in batches using Vec for intermediate steps:
$batch = Vec::fromArray($records)->chunk(100);
foreach ($batch as $chunk) {
$processed = $chunk->map(fn($record) => processRecord($record));
// Save $processed
}
API Response Handling: Standardize API response transformations:
$response = Vec::fromArray($apiData)
->map(fn($item) => (new ApiResponseDto($item))->format())
->toArray();
Type Hints: Use PHPDoc or PHP 8.2+ attributes for better IDE support:
/** @var Vec<int, string> */
$names = Vec::fromArray(['Alice', 'Bob']);
// Or with PHP 8.2+
#[ArrayType(elementType: 'int', valueType: 'string')]
public function getNames(): Vec { ... }
Custom Methods:
Extend Vec with domain-specific methods:
Vec::macro('sum', function (Vec $vec) {
return $vec->reduce(0, fn($sum, $n) => $sum + $n);
});
$total = Vec::fromArray([1, 2, 3])->sum(); // Returns 6
Testing:
Use Vec in tests for predictable, immutable data:
public function testUserTransformation() {
$users = Vec::fromArray([['name' => 'Alice'], ['name' => 'Bob']]);
$result = $users->map(fn($user) => $user['name']);
$this->assertEquals(['Alice', 'Bob'], $result->toArray());
}
Performance Considerations:
Vec for readability over raw arrays in non-critical paths.Collection for performance-sensitive operations:
$vecTime = Benchmark::measure(fn() => Vec::fromArray($data)->map(...));
$collectionTime = Benchmark::measure(fn() => collect($data)->map(...));
Strict Indexing:
Vec enforces 0-indexed, sequential arrays. Passing associative arrays will throw errors:
// Throws exception
Vec::fromArray(['a' => 1, 'b' => 2]);
Fix: Use Vec::fromArray(array_values($assocArray)) or validate inputs.
Method Shadowing:
Vec methods like map, filter, and reduce may conflict with Laravel’s Collection if not scoped carefully:
// Avoid confusion
$vec = Vec::fromArray($data)->map(...);
$collection = collect($data)->map(...); // Different behavior!
Fix: Use explicit namespaces or aliases (e.g., Vec::map() vs. Collection::map()).
Immutability:
Methods like push or pop return new Vec instances, which may surprise developers used to in-place mutations:
$vec = Vec::fromArray([1, 2]);
$newVec = $vec->push(3); // Original $vec is unchanged
Fix: Document immutability expectations in your team’s style guide.
No Laravel Facade:
Unlike Laravel’s Collection, Vec has no built-in facade or service provider. You’ll need to manually instantiate it:
// Not available
Vec::make([1, 2, 3]);
// Use instead
Vec::fromArray([1, 2, 3]);
Fix: Create a helper class or facade if needed:
class VecHelper {
public static function make(array $array): Vec {
return Vec::fromArray($array);
}
}
Edge Cases in reduce:
The reduce method may behave unexpectedly with empty Vec instances:
$emptyVec = Vec::empty();
$result = $emptyVec->reduce(0, fn($sum, $n) => $sum + $n);
// Returns 0 (not an error)
Fix: Handle empty cases explicitly:
$result = $vec->isEmpty() ? [] : $vec->reduce(...);
Inspect Vec Contents:
Use toArray() for debugging:
$vec = Vec::fromArray([1, 2, 3])->map(fn($n) => $n * 2);
dd($vec->toArray()); // [2, 4, 6]
Validate Inputs:
Ensure inputs are indexed arrays before passing to Vec:
if (!is_array($data) || array_keys($data) !== range(0, count($data) - 1)) {
throw new InvalidArgumentException('Data must be a sequential array.');
}
Custom Error Handling: Override error handling for production:
Vec::setErrorHandler(function (Throwable $e) {
Log::error("Vec
How can I help you explore Laravel packages today?