A collection library for PHP.
Two types of collections are available:
- Sets (
MutableSet
andImmutableSet
), are sequences of unique values. Values can be of any types. - Map (
MutableMap
andImmutableMap
), 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/multitude
This 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