mf / collections-php
Collections for PHP - It's basically a syntax sugar over classic array structure, which allows you to use it as classic array, but adds some cool features.
Installs: 75 709
Dependents: 7
Suggesters: 0
Security: 0
Stars: 10
Watchers: 4
Forks: 0
Open Issues: 1
Requires
- php: ^8.2
- ext-mbstring: *
- beberlei/assert: ^3.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.40
- lmc/coding-standard: ^3.3
- mockery/mockery: ^1.6.7
- php-parallel-lint/php-parallel-lint: ^1.3.2
- phpstan/extension-installer: ^1.3.1
- phpstan/phpstan: ^1.10.49
- phpstan/phpstan-beberlei-assert: ^1.1.2
- phpstan/phpstan-mockery: ^1.1.1
- phpstan/phpstan-phpunit: ^1.3.15
- phpunit/phpunit: ^10.5.3
- symfony/var-dumper: ^7.0
- dev-master
- 8.3.0
- 8.2.0
- 8.1.1
- 8.1.0
- 8.0.0
- v7.x-dev
- 7.2.0
- 7.1.1
- 7.1.0
- 7.0.0
- 6.1.1
- 6.1.0
- 6.0.0
- v5.x-dev
- 5.0.1
- 5.0.0
- 4.0.0
- 3.18.0
- 3.17.0
- 3.16.1
- 3.16.0
- 3.15.0
- 3.14.0
- 3.13.0
- 3.12.0
- 3.11.0
- 3.10.0
- 3.9.0
- 3.8.0
- 3.7.0
- 3.6.0
- 3.5.1
- 3.5.0
- 3.4.2
- 3.4.1
- 3.3.0
- 3.2.2
- 3.2.1
- 3.2.0
- 3.1.1
- 3.0.1
- 3.0.0
- 2.1.0
- 2.0.1
- 2.0.0
- 1.0.0
- dev-feature/update-cs
This package is auto-updated.
Last update: 2024-10-27 08:09:48 UTC
README
It's basically a syntax sugar over classic array structure, which allows you to use it as classic array, but adds some cool features.
Table of Contents
- Installation
- Requirements
- Base Interfaces
- Mutable
- Immutable
- Generic
- Arrow Functions
- Plans for next versions
Installation
composer require mf/collections-php
Requirements
PHP ^8.2
Base Interfaces
Check out Documentation for more details.
IEnumerable
- basic Interface for enumerable
- extends
IteratorAggregate
,Countable
- see Immutable tuple
- see Mutable PrioritizedCollection
ICollection
- basic Interface for Collections
- extends
IEnumerable
- see Mutable collections
- see Immutable collections
IList
A list is an ordered (possibly immutable) series of elements of the same type.
- extends
ICollection
- see Mutable list
- see Immutable list
IMap
A map is an ordered (possibly immutable) series of key values pairs.
- extends
ICollection, ArrayAccess
- see Mutable map
- see Immutable map
ISeq
A sequence is a logical series of elements all of one type.
- extends
ICollection
- see Immutable seq
ITuple
A tuple is a grouping of unnamed but ordered values, possibly of different types.
- extends
IEnumerable
,ArrayAccess
,Stringable
- see Immutable tuple
Mutable Collections
Interfaces
Mutable\Generic\ICollection
,Mutable\Generic\IList
,Mutable\Generic\IMap
Mutable\Generic\ListCollection
- implements
Mutable\Generic\IList
- is
eager
as possible
Mutable\Generic\Map
- implements
Mutable\Generic\IMap
- is
eager
as possible
Mutable\Generic\PrioritizedCollection
- implements
IEnumerable
- holds items with
generic
type bypriority
- is
eager
as possible
Example of strategies by priority
For case when you want to apply only the first strategy
which can do what you want.
You can add strategies dynamically
and still apply them by priority
later.
// initialization of strategies /** @phpstan-var PrioritizedCollection<StrategyInterface> $strategies */ $strategies = new PrioritizedCollection(); $strategies->add(new DefaultStrategy(), 1); // added later $strategies->add(new SpecialStrategy(), 100); // find and apply first suitable strategy /** @var StrategyInterface $strategy */ foreach ($strategies as $strategy) { if ($strategy->supports($somethingStrategic)) { return $strategy->apply($somethingStrategic); } }
Immutable Collections
internal state
of Immutable\Collection instance willnever change
from the outside (it isreadonly
)
$list = new Immutable\ListCollection(); $listWith1 = $list->add(1); // $list != $listWith1 echo $list->count(); // 0 echo $listWith1->count(); // 1
$list
is still an emptyImmutable\ListCollection
$listWith1
is new instance ofImmutable\ListCollection
with value1
Interfaces
Immutable\Generic\ICollection
,Immutable\Generic\IList
,Immutable\Generic\IMap
,Immutable\Generic\ISeq
,Immutable\ITuple
Immutable\Generic\ListCollection
- implements
Immutable\Generic\IList
- is
eager
as possible
Immutable\Generic\Map
- implements
Immutable\Generic\IMap
- is
eager
as possible
Immutable\Seq
- implements
Immutable\Generic\ISeq
- is
lazy
as possible (even could beInfinite
)
$seq = Seq::infinite() // 1, 2, ... ->filter(fn ($i) => $i % 2 === 0) // 2, 4, ... ->skip(2) // 6, 8, ... ->map(fn ($i) => $i * $i) // 36, 64, ... ->takeWhile(fn ($i) => $i < 100) // 36, 64 ->reverse() // 64, 36 ->take(1); // 64 // for now the Sequence is still lazy // this will generate (evaluate) the values $array = $seq->toArray(); // [64]
Immutable\Generic\KVPair
- always has a
Key
and theValue
- key is restricted to
int|string
so it may be used in theforeach
as a key - can contain any values
Immutable\Tuple
- implements
Immutable\ITuple
- must have at least 2 values (otherwise it is just a single value)
- is
eager
as possible - allows
destructuring
,matching
andparsing
/formatting
- can contain any scalar values and/or arrays
- in string representation of a
Tuple
, array values must be separated by;
(not by,
)
- in string representation of a
Parsing
Tuple::parse('(foo, bar)')->toArray(); // ['foo', 'bar'] Tuple::parse('("foo, bar", boo)')->toArray(); // ['foo, bar', 'boo'] Tuple::parse('(1, "foo, bar", true)')->toArray(); // [1, 'foo, bar', true] Tuple::parse('(1, [2; 3], [four; "Five"])')->toArray(); // [1, [2, 3], ['four', 'five']]
Matching and comparing
Tuple::from([1, 1])->match('int', 'int'); // true Tuple::from([1, 2, 3])->isSame(Tuple::of(1, 2, 3)); // true Tuple::of(10, 'Foo', null)->match('int', 'string', '?string'); // true Tuple::of(10, [9, 8])->match('int', 'array'); // true
Parsing and matching
Tuple::parseMatch('(foo, bar)', 'string', 'string')->toArray(); // ['foo', 'bar'] Tuple::parseMatchTypes('(foo, bar)', ['string', 'string'])->toArray(); // ['foo', 'bar'] // invalid types Tuple::parseMatch('(foo, bar, 1)', 'string', 'string'); // throws \InvalidArgumentException "Given tuple does NOT match expected types (string, string) - got (string, string, int)"
Formatting
Tuple::from([1, 'foo', null])->toString(); // '(1, "foo", null)' // for URL Tuple::from(['foo', 'bar'])->toStringForUrl(); // '(foo,bar)' Tuple::from(['foo-bar', 'boo'])->toStringForUrl(); // '(foo-bar,bar)' Tuple::from(['mail', 'a@b.com'])->toStringForUrl(); // '(mail,"a@b.com")'
Destructuring
$tuple = Tuple::of('first', 2, 3); // ('first', 2, 3) $first = $tuple->first(); // 'first' $second = $tuple->second(); // 2 [$first, $second] = $tuple; // $first = 'first'; $second = 2 [,, $third] = $tuple; // 3
Unpacking
sprintf('Title: %s | Value: %s', ...Tuple::of('foo', 'bar')); // "Title: foo | Value: bar"
Merging
- merging
Tuples
will automatically flat them (see last example below)
$base = Tuple::of('one', 'two'); // ('one', 'two') $upTo3 = Tuple::merge($base, 'three'); // ('one', 'two', 'three') $upTo4 = Tuple::merge($base, '3', 'four'); // ('one', 'two', '3', 'four') $upTo5 = Tuple::merge($base, ['3', '4'], '5'); // ('one', 'two', ['3', '4'], '5') $upTo5 = Tuple::merge($base, Tuple::of('3', '4'), '5'); // ('one', 'two', '3', '4', '5')
Merging and matching
$base = Tuple::of('one', 'two'); // ('one', 'two') $upTo3 = Tuple::mergeMatch(['string', 'string', 'int'], $base, 3); // ('one', 'two', 3) // invalid types Tuple::mergeMatch(['string', 'string'], $base, 3); // throws \InvalidArgumentException "Merged tuple does NOT match expected types (string, string) - got (string, string, int)."
Sequences and lazy mapping
- if your
Sequence
get mapped and filtered many times (for readability), it is not a problemmap -> map -> filter -> map -> filter -> map
will iterate the collection only once (for applying all modifiers at once)- this modification is done when another method is triggered, so adding new modifier is an atomic operation
- all the values are generated on the fly, so it may end on out of memory exception
Plans for next versions
- use
Symfony/Stopwatch
in unit tests - even better documentation (current)