shrikeh/collections

Traits for re-use in immutable collections

v1.0.4 2017-01-03 13:58 UTC

This package is auto-updated.

Last update: 2024-05-06 02:50:34 UTC


README

build_status_img code_quality_img latest_stable_version_img latest_unstable_version_img license_img twitter_img

Trait-based helper library to take care of the heavy lifting of immutable collections in PHP.

Overview

This low-level library is just time-saving traits for creating immutable collections. As PHP 7 can use return type hinting, I decided I would always return a Collection if there was a possibility of returning 0-n objects from a method, and could then type hint the return value as a Collection, whether empty or not. PHP does not natively support immutable iterators, so I find that whenever I use Domain-Driven Design, and need an iterable list of Value Objects, I have to do the same boilerplate re-work.

This pattern has been successful for me, as I can also strongly type the Collections themselves, so they can only contain objects of a given type. I also generally make them immutable, so they throw a descendent of DomainException if you try to set or unset a value.

So as I use these more often, I split them up into Traits for re-use across my code. Feel free to use for yourself, they're tiny and just take care of boilerplate stuff for me.

Installation

Recommended installation is via the ubiquitous and seminal composer:

composer require --prefer-dist shrikeh/collections

Usage

The library consists of about a dozen traits that aid in matching core PHP and SPL interfaces such as ArrayAccess and OuterIterator. Generally I have an inner "storage", and ensure that access to this directly is removed, including mutable methods such as offSetSet() or offsetUnset(). This ensures that only the values added to the constructor can be iterated over.

As an example, to create a Collection that can only contain SomeObject objects:

<?php

namespace Shrikeh\Collection\Examples;

use IteratorIterator;
use Shrikeh\Collection\Examples\SomeObject;

/**
 * An immutable iterator that can only contain SomeObject objects.
 */
final class ImmutableSomeObjectCollection extends IteratorIterator
{
    use \Shrikeh\Collection\NamedConstructorsTrait;   # Give it named constructors
    use \Shrikeh\Collection\ImmutableCollectionTrait; # Give it read-only array access
    use \Shrikeh\Collection\ClosedOuterIteratorTrait; # Close off access to the inner iterator
    use \Shrikeh\Collection\OuterIteratorTrait;       # Give it all the standard read access methods
    use \Shrikeh\Collection\ObjectStorageTrait;       # Set inner storage to SplObjectStorage

    # Append method is called by ObjectStorageTrait during construction, so we
    # type hint the relevant class/interface we need...
    protected function append(SomeObject $object, $key)
    {
        $this->getStorage()->attach($object);
    }
}

Please take a look in the examples and the specs for further usage.

Traits

ArrayAccessTrait

Used to easily meet the requirements of the ArrayAccess interface. Proxies to underlying offsetX methods of the storage.

ClosedOuterIteratorTrait

The OuterIterator interface specifies that a class must implement the method getInnerIterator, and the visibility of this method cannot be changed from public. This defeats the point of having an immutable Collection. Therefore, this trait, when applied, causes the class to throw a ClosedOuterIterator exception for this method.

FixedArrayStorageTrait

This provides a public __construct() method consistent with the IteratorIterator family of SPL classes, providing the class with a SplFixedArray storage (SplFixedArray, sadly, can have it's size changed after instanstiation).

ImmutableArrayAccessTrait

This trait "switches off" the offsetSet() and offsetUnset() methods required by the ArrayAccess interface. Attempting to use either will result in a ImmutableCollection exception being thrown.

ImmutableCollectionTrait

This trait is a shorthand for including the ArrayAccessTrait and then overriding the setters with ImmutableArrayAccessTrait.

NamedConstructorsTrait

Provides the named constructors fromTraversable() and fromArray() to a Collection.

ObjectStorageTrait

This provides a public __construct() method consistent with the IteratorIterator family of SPL classes, providing the class with a SplObjectStorage inner storage.

OuterIteratorTrait

If you don't want to extend any of the IteratorIterator family, but do want to implement OuterIterator, this trait provides the necessary methods that proxy to the inner storage.

RequiresOuterIteratorTrait

"Safety catch" trait used by FixedArrayStorageTrait and ObjectStorageTrait to ensure the class using the trait implements OuterIterator. Throws an IncorrectInterface Exception if not.