The Collection library provides a flexible and efficient API to manipulate, iterate, and manage collections in a
structured and type-safe manner.
It leverages PHP's Generators for optimized memory usage and lazy evaluation, ensuring that large datasets are handled efficiently without loading all elements into memory at once.
The library supports adding, removing, filtering, sorting, and transforming elements.
composer require tiny-blocks/collectionThe library exposes the available behaviors through the Collectible interface and provides utilities to manipulate
collections of various types.
The Collection class implements the Collectible interface and provides a concrete implementation for handling
collections.
It allows for adding, removing, filtering, and sorting elements, as well as transforming them into different formats like arrays and JSON.
The class is designed to work with generic key-value pairs, ensuring type safety and flexibility for a variety of use cases.
<?php
declare(strict_types=1);
namespace Example;
use TinyBlocks\Collection\Collection;
use TinyBlocks\Collection\Order;
use TinyBlocks\Mapper\KeyPreservation;
$collection = Collection::createFrom(elements: [1, 2, 3, 4, 5])
->add(6, 7)
->filter(predicates: static fn(int $value): bool => $value > 3)
->sort(order: Order::ASCENDING_VALUE)
->map(transformations: static fn(int $value): int => $value * 2)
->toArray(keyPreservation: KeyPreservation::DISCARD);
# Output: [8, 10, 12, 14]Domain collections should extend the Collection class to inherit all collection behavior:
<?php
declare(strict_types=1);
namespace Example;
use TinyBlocks\Collection\Collection;
final class Invoices extends Collection
{
public function totalAmount(): float
{
return $this->reduce(
accumulator: static fn(float $carry, Invoice $invoice): float => $carry + $invoice->amount,
initial: 0.0
);
}
}These methods enable adding, removing, and modifying elements in the Collection.
-
add: Returns a new collection with the specified elements appended.$collection->add(1, 2, 3);
$collection->add('X', 'Y', 'Z');
-
merge: Merges the elements of another Collectible into the current Collection.$collectionA->merge(other: $collectionB);
-
remove: Returns a new collection with all occurrences of the specified element removed.$collection->remove(element: 1);
-
removeAll: Returns a new collection with elements removed.-
With a predicate: Removes only the elements that satisfy the given predicate.
$collection->removeAll(predicate: static fn(Amount $amount): bool => $amount->value > 10.0);
-
Without a predicate: Removes all elements from the Collection.
$collection->removeAll();
-
These methods enable filtering elements in the Collection based on specific conditions.
-
filter: Retains only elements satisfying all given predicates.-
With predicates: Retains elements that satisfy the provided predicates.
$collection->filter(predicates: static fn(Amount $amount): bool => $amount->value > 100);
-
Without predicates: Removes all falsy values (e.g.,
null,false,0,'', empty arrays).$collection->filter();
-
These methods enable sorting elements in the Collection based on the specified order and optional comparator.
-
sort: Returns a new sorted collection.Order::ASCENDING_KEY: Sorts the collection in ascending order by key. Order::DESCENDING_KEY: Sorts the collection in descending order by key. Order::ASCENDING_VALUE: Sorts the collection in ascending order by value. Order::DESCENDING_VALUE: Sorts the collection in descending order by value.By default,
Order::ASCENDING_KEYis used.use TinyBlocks\Collection\Order; $collection->sort(order: Order::DESCENDING_VALUE);
Sort the Collection using a custom comparator to determine how elements should be compared.
use TinyBlocks\Collection\Order; $collection->sort( order: Order::ASCENDING_VALUE, comparator: static fn(Amount $first, Amount $second): int => $first->value <=> $second->value );
These methods allow access to elements within the Collection, such as fetching the first or last element, counting the elements, or finding elements that match a specific condition.
-
count: Returns the total number of elements in the Collection.$collection->count();
-
isEmpty: Determines whether the collection has no elements.$collection->isEmpty();
-
findBy: Finds the first element that satisfies any given predicate, or returnsnullif no predicate matches. When called without predicates, it returnsnull.$collection->findBy(predicates: static fn(CryptoCurrency $crypto): bool => $crypto->symbol === 'ETH');
-
first: Retrieves the first element from the Collection or returns a default value if the Collection is empty.$collection->first(defaultValueIfNotFound: 'fallback');
-
getBy: Retrieves an element by its zero-based index or returns a default value if the index is out of bounds.$collection->getBy(index: 0, defaultValueIfNotFound: 'fallback');
-
last: Retrieves the last element from the Collection or returns a default value if the Collection is empty.$collection->last(defaultValueIfNotFound: 'fallback');
-
slice: Extracts a contiguous segment of the collection, starting at the specified offset. If length is negative, it excludes that many elements from the end. If length is not provided or set to -1, it returns all elements from the specified offset to the end.$collection->slice(offset: 1, length: 2);
These methods enable comparing collections to check for equality or to verify element membership.
-
contains: Checks if the Collection contains a specific element. Uses strict equality for scalars and loose equality for objects.$collection->contains(element: 5);
-
equals: Compares the current Collection with another collection for element-wise equality.$collectionA->equals(other: $collectionB);
These methods perform operations that return a single value based on the Collection's content, such as summing or combining elements.
-
reduce: Combines all elements in the Collection into a single value using the provided accumulator function and an initial value. This method is helpful for accumulating results, like summing or concatenating values.$collection->reduce( accumulator: static fn(float $carry, float $amount): float => $carry + $amount, initial: 0.0 );
-
joinToString: Joins all elements into a string with the given separator.$collection->joinToString(separator: ', ');
These methods allow the Collection's elements to be transformed or converted into different formats.
-
each: Executes actions on each element in the Collection without modification. The method is helpful for performing side effects, such as logging or accumulating values.$collection->each(actions: static fn(Amount $amount): void => $total += $amount->value);
-
groupBy: Groups the elements in the Collection based on the provided classifier.$collection->groupBy(classifier: static fn(Amount $amount): string => $amount->currency->name);
-
map: Applies transformations to each element in the Collection and returns a new collection with the transformed elements.$collection->map(transformations: static fn(int $value): int => $value * 2);
-
flatten: Flattens nested iterables by exactly one level. Non-iterable elements are yielded as-is.$collection->flatten();
-
toArray: Converts the Collection into an array.KeyPreservation::DISCARD: Converts while discarding the keys. KeyPreservation::PRESERVE: Converts while preserving the original keys.By default,
KeyPreservation::PRESERVEis used.use TinyBlocks\Mapper\KeyPreservation; $collection->toArray(keyPreservation: KeyPreservation::DISCARD);
-
toJson: Converts the Collection into a JSON string.KeyPreservation::DISCARD: Converts while discarding the keys. KeyPreservation::PRESERVE: Converts while preserving the original keys.By default,
KeyPreservation::PRESERVEis used.use TinyBlocks\Mapper\KeyPreservation; $collection->toJson(keyPreservation: KeyPreservation::DISCARD);
The Collection class leverages PHP's Generators to
provide lazy evaluation, meaning elements are only generated as needed.
It cannot be reused once a generator is consumed (i.e., after you iterate over it or apply certain operations).
This behavior is intended to optimize memory usage and performance but can sometimes lead to confusion when reusing an
iterator after operations like count, toJson, or toArray.
Lazy evaluation, enabled by PHP's Generators, allows
Collection to handle large datasets without loading all elements into memory at once.
This results in significant memory savings when working with large datasets or performing complex chained operations.
However, this also means that some operations will consume the generator, and you cannot access the elements unless you
recreate the Collection.
-
Eager evaluation (
createFrom/createFromEmpty): Elements are materialized immediately into an array, enabling constant-time access by index, count, and repeated iteration. -
Lazy evaluation (
createLazyFrom/createLazyFromEmpty): Elements are processed on-demand through generators, consuming memory only as each element is yielded. Ideal for large datasets or pipelines where not all elements need to be materialized.
Collection is licensed under MIT.
Please follow the contributing guidelines to contribute to the project.