GithubHelp home page GithubHelp logo

mortalflesh / mfcollectionsphp Goto Github PK

View Code? Open in Web Editor NEW
10.0 4.0 0.0 624 KB

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.

Home Page: https://github.com/MortalFlesh/MFCollectionsPHP/wiki

License: MIT License

PHP 100.00%
immutable-collections generic-collections mutable-collections php syntax-sugar collections collection generic-interface immutable generic

mfcollectionsphp's Introduction

MFCollections for PHP

Latest Stable Version Total Downloads License Tests and linting Coverage Status

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

composer require mf/collections-php

Requirements

  • PHP ^8.2

Base Interfaces

Check out Documentation for more details.

IEnumerable

ICollection

IList

A list is an ordered (possibly immutable) series of elements of the same type.

IMap

A map is an ordered (possibly immutable) series of key values pairs.

ISeq

A sequence is a logical series of elements all of one type.

ITuple

A tuple is a grouping of unnamed but ordered values, possibly of different types.

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 by priority
  • 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 will never change from the outside (it is readonly)
$list = new Immutable\ListCollection();
$listWith1 = $list->add(1);

// $list != $listWith1
echo $list->count();        // 0
echo $listWith1->count();   // 1
  • $list is still an empty Immutable\ListCollection
  • $listWith1 is new instance of Immutable\ListCollection with value 1

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 be Infinite)
$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 the Value
  • key is restricted to int|string so it may be used in the foreach 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 and parsing/formatting
  • can contain any scalar values and/or arrays
    • in string representation of a Tuple, array values must be separated by ; (not by ,)

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', '[email protected]'])->toStringForUrl(); // '(mail,"[email protected]")'

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 problem
    • map -> 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)

mfcollectionsphp's People

Contributors

mortalflesh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

mfcollectionsphp's Issues

question

Hey,

I'm implementing my version of a collection and today I introduced lazy method calls. however when I measure lazy v.s. non-lazy, non-lazy wins every time with quite a large margin. I am very curious how and by what margin your lazy mapping improves performance :D

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.