A collection library for PHP.
Two types of collections are available:
- Sets (
MutableSetandImmutableSet), are sequences of unique values. Values can be of any types. - Map (
MutableMapandImmutableMap), is a sequential collection of key-value pairs. Keys can be any type, but must be unique. Values can be of any types.
In both ImmutableSet and ImmutableMap, if a method alter the content af the inner values, a new instance is returned of the same type. Oppositely, in MutableSet and MutableMap, same methods are altering the inner values.
Methods are the most possible fluent.
Thanks to https://github.com/BenMorel for the main ideas used in that library, this is a complete rewrite of it's initial version.
This library is installable via Composer:
composer require micoli/multitudeThis library requires PHP 8.0 or later.
While this library is still under development, it is still in early development status. It follows semver version tagging.
Constructor are only statics:
new MutableSet(['a','b','c'])new MutableMap([2=>'a',3=>'b',4=>'c'])new MutableMap([[2,'a'],['2','aa'],[3,'b'],['3','bb'],[4,'c'])
You can use fromTuples constructor if you need a strong typing for keys of your map, e.g. '2' key is different of 2.
Methods that accept a bool $throw parameter will trigger an exception if $throw == true or fails silently if $throw == false.
public function testItShouldFullyWorkWithAssociativeArray(): void
{
/** @var ImmutableMap<string, array{value:int,tags:list<string>}> $map */
$map = new ImmutableMap([
['library', ['value' => 10, 'tags' => ['tag1']]],
['projects', ['value' => 5, 'tags' => ['tag2']]],
['gist', ['value' => 7, 'tags' => ['tag1', 'tag2']]],
['repository', ['value' => 7, 'tags' => ['tag3']]],
]);
$totalSum = $map
->filter(fn (array $project, mixed $category): bool => array_search('tag1', $project['tags']) !== false)
->reduce(fn (int $sum, mixed $project, mixed $category): int => $sum + $project['value'], 0);
self::assertSame($totalSum, 17);
self::assertCount(4, $map);
}File: Project.php
<?php
declare(strict_types=1);
namespace Micoli\Multitude\Tests\Fixtures;
class Project
{
public function __construct(
public readonly int $value,
public readonly Tags $tags,
) {
}
}File: Tags
<?php
declare(strict_types=1);
namespace Micoli\Multitude\Tests\Fixtures;
use Micoli\Multitude\Set\ImmutableSet;
/**
* @extends ImmutableSet<string>
*/
class Tags extends ImmutableSet
{
}File: Projects
<?php
declare(strict_types=1);
namespace Micoli\Multitude\Tests\Fixtures;
use Micoli\Multitude\Map\ImmutableMap;
/**
* @extends ImmutableMap<string, Project>
*/
class Projects extends ImmutableMap
{
/**
* Add or replace a value in the map
*/
public function improvedSet(string $newKey, Project $newValue): static
{
// do specific stuff, like logging or ther
return $this->set($newKey, $newValue);
}
} public function testItShouldFullyWorkWithObjects(): void
{
$map = new Projects([
['library', new Project(10, new Tags(['tag1']))],
['projects', new Project(5, new Tags(['tag2']))],
['gist', new Project(7, new Tags(['tag1', 'tag2']))],
['repository', new Project(7, new Tags(['tag3']))],
]);
$totalSum = $map
->filter(fn (Project $project, mixed $category): bool => $project->tags->hasValue('tag1'))
->reduce(fn (int $sum, Project $project, mixed $category): int => $sum + $project->value, 0);
self::assertInstanceOf(
Projects::class,
$map->filter(fn (Project $project, mixed $category): bool => true),
);
self::assertSame($totalSum, 17);
self::assertCount(4, $map);
$newMap = $map->improvedSet('NewType', new Project(10, new Tags(['tag4'])));
self::assertCount(5, $newMap);
}| ImmutableMap | MutableMap | ImmutableSet | MutableSet | |
|---|---|---|---|---|
| __construct | [x] | [x] | [x] | [x] |
| append | [x] | [x] | ||
| apply | [x] | [x] | [x] | [x] |
| count | [x] | [x] | [x] | [x] |
| filter | [x] | [x] | [x] | [x] |
| first | [x] | [x] | [x] | [x] |
| forEach | [x] | [x] | [x] | [x] |
| fromIterable | [x] | [x] | ||
| get | [x] | [x] | [x] | [x] |
| getIterator | [x] | [x] | [x] | [x] |
| getTuples | [x] | [x] | ||
| hasIndex | [x] | [x] | ||
| hasKey | [x] | [x] | ||
| hasValue | [x] | [x] | [x] | [x] |
| indexDiff | [x] | [x] | ||
| indexIntersect | [x] | [x] | ||
| isEmpty | [x] | [x] | [x] | [x] |
| keyDiff | [x] | [x] | ||
| keyIntersect | [x] | [x] | ||
| keys | [x] | [x] | [x] | [x] |
| ImmutableMap | MutableMap | ImmutableSet | MutableSet | |
| last | [x] | [x] | [x] | [x] |
| map | [x] | [x] | [x] | [x] |
| offsetExists | [x] | [x] | ||
| offsetGet | [x] | [x] | ||
| offsetSet | [x] | [x] | ||
| offsetUnset | [x] | [x] | ||
| reduce | [x] | [x] | [x] | [x] |
| remove | [x] | [x] | ||
| removeKey | [x] | [x] | ||
| removeValue | [x] | [x] | ||
| set | [x] | [x] | ||
| slice | [x] | [x] | [x] | [x] |
| sort | [x] | [x] | [x] | [x] |
| toArray | [x] | [x] | [x] | [x] |
| toImmutable | [x] | [x] | ||
| toMutable | [x] | [x] | ||
| valueDiff | [x] | [x] | [x] | [x] |
| valueIntersect | [x] | [x] | [x] | [x] |
| values | [x] | [x] | [x] | [x] |
- __construct
- append
- apply
- count
- filter
- first
- forEach
- get
- getIterator
- hasIndex
- hasValue
- indexDiff
- indexIntersect
- isEmpty
- keys
- last
- map
- reduce
- remove
- slice
- sort
- toArray
- valueDiff
- valueIntersect
- values
- __construct
- apply
- count
- filter
- first
- forEach
- fromIterable
- get
- getIterator
- getTuples
- hasKey
- hasValue
- isEmpty
- keyDiff
- keyIntersect
- keys
- last
- map
- offsetExists
- offsetGet
- offsetSet
- offsetUnset
- reduce
- removeKey
- removeValue
- set
- slice
- sort
- toArray
- valueDiff
- valueIntersect
- values
public function __construct(iterable $values = [])
public function append(mixed $newValue, bool $throw = true): static
Append a value at the end of the set
public function apply(callable $callable): static
Replace all values by applying a callback to the current instance
public function count(): int
return the number of items in the set
public function filter(callable $callable): static
Filter the set using a callback function
public function first(bool $throw = true): mixed
Return the first value in the set
public function forEach(callable $callable): static
Apply a callback on set values
Callback receive $value and $index
public function get(int $index, mixed $defaultValue = null): mixed
Return a value in the set by index
public function getIterator(): Traversable
Return an iterator for values
public function hasIndex(int $index): bool
Return if a set contains an index
public function hasValue(mixed $searchedValue): bool
Return if a set contains a value
public function indexDiff(AbstractSet $compared): static
Return a set of all items where keys are not in argument set
public function indexIntersect(AbstractSet $compared): static
Return a map of all items where keys are in arguments map
public function isEmpty(): bool
Return if a set is empty
public function keys(): Generator
Return an iterator of keys
public function last(bool $throw = true): mixed
Return the latest value in the set
public function map(callable $callable)
Applies the callback to the values, keys are preserved
Callback receive $value and $index
public function reduce(callable $callable, mixed $accumulator): mixed
Iteratively reduce the Set to a single value using a callback function
Callback receive $accumulator,$value and $index
public function remove(mixed $searchedValue, bool $throw = true): static
Remove a value in the set
public function slice(int $offset, ?int $length = null): static
Extract a slice of the set
public function sort(callable $callable): static
Sort the map using a callback function
callback is of callable (TValue, TValue, int, int): int
and must return -1,0,1 as spaceship operator
public function toArray(): array
Return an array representing the values
public function valueDiff(AbstractSet $compared): static
Return a Set of all items where values are not in argument set
public function valueIntersect(AbstractSet $compared): static
Return a set of all items where values are in argument set
public function values(): Generator
Return an iterator of values
public function __construct(array $tuples = [])
public function apply(callable $callable): static
Replace all values by applying a callback to the current instance
public function count(): int
Return the number of items in the map
public function filter(callable $callable): static
Filter the map using a callback function
public function first(bool $throw = true): mixed
Return the first value in the map
public function forEach(callable $callable): static
Apply a callback on set values
public static function fromIterable(iterable $values): static
Return a new instance from an array.
public function get(mixed $searchedKey, mixed $defaultValue = null): mixed
Return a value in the map by index
public function getIterator(): Traversable
Return an iterator for values by keys
public function getTuples(): array
public function hasKey(mixed $searchedKey): bool
Return if a map contains a specific key
public function hasValue(mixed $searchedValue): bool
Return if a map contains a specific value
public function isEmpty(): bool
Return if a map is empty
public function keyDiff(AbstractMap $compared): static
Return a map of all items where keys are not in argument map
public function keyIntersect(AbstractMap $compared): static
Return a map of all items where keys are in arguments map
public function keys(): Generator
Return an iterator of keys
public function last(bool $throw = true): mixed
Return the latest value in the map
public function map(callable $callable)
Applies the callback to the values, keys are preserved
public function offsetExists(mixed $offset): bool
public function offsetGet(mixed $offset): mixed
public function offsetSet(mixed $offset, mixed $value): void
public function offsetUnset(mixed $offset): void
public function reduce(callable $callable, mixed $accumulator): mixed
Iteratively reduce the Map to a single value using a callback function
Callback receive $accumulator,$value and $key
public function removeKey(mixed $searchedKey): static
Remove a value in the map by key
public function removeValue(mixed $searchedValue): static
Remove a value in the map by value
public function set(mixed $newKey, mixed $newValue): static
Add or replace a value in the map
public function slice(int $offset, ?int $length = null): static
Extract a slice of the map
public function sort(callable $callable): static
Sort the map using a callback function
callback is of callable(TValue, TValue, TKey, TKey, int, int): int
and must return -1,0,1 as spaceship operator
public function toArray(): array
Return an array representing the values
public function valueDiff(AbstractMap $compared): static
Return a map of all items where values are not in arguments map
public function valueIntersect(AbstractMap $compared): static
Return a map of all items where values are in argument map
public function values(): Generator
Return an iterator of values