php-immutable-collections
![build_status_img]
[!code_quality_img][code_quality]
![latest_stable_version_img]
![latest_unstable_version_img]
![license_img]
![twitter_img], (*1)
Trait-based helper library to take care of the heavy lifting of immutable collections in PHP., (*2)
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., (*3)
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., (*4)
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., (*5)
Installation
Recommended installation is via the ubiquitous and seminal composer
:, (*6)
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., (*7)
As an example, to create a Collection that can only contain SomeObject
objects:, (*8)
<?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., (*9)
Traits
Used to easily meet the requirements of the ArrayAccess interface. Proxies to underlying offsetX
methods of the storage., (*10)
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., (*11)
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)., (*12)
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., (*13)
This trait is a shorthand for including the ArrayAccessTrait
and then overriding the setters with ImmutableArrayAccessTrait
., (*14)
Provides the named constructors fromTraversable()
and fromArray()
to a Collection., (*15)
This provides a public __construct()
method consistent with the IteratorIterator
family of SPL classes, providing the class with a SplObjectStorage
inner storage., (*16)
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., (*17)
"Safety catch" trait used by FixedArrayStorageTrait
and ObjectStorageTrait
to ensure the class using the trait implements OuterIterator
. Throws an IncorrectInterface
Exception if not., (*18)