Initially this lib started to as an ArrayObject
implementation mimicking JavaScripts
Array
object, featuring immutability and fluent interface.
The project goal shifted towards efficiently support PHPs Traversable
like they happen
when consuming huge amounts of data. That immediately meant dropping the immutability
since that whould mean copying the state on every operation.
The plain ArrayObject
has no mutating operation. There is ArrayObect::count()
as well
as ArrayObject::getIterator()
, but both don't change the object state. They just conform
the Countable
and the IteratorAggregate
for being able to iterate over the result.
Every other operation, like ArrayObject::map()
, ArrayObject::filter()
and many others,
comes as a plug in. That means it could in theory be swapped by different implementation or
extended by additional operations. Although I know that's pretty unlikely to happen.
There's a public static method ArrayObject::registerMethod()
that adds new mutation
operators to the ArrayObject
implementation.
<?PHP
use StephanSchuler\ArrayObject as AryO;
$noop = function(\Traversable $data): \Traversable
{
foreach ($data as $key => $value) {
yield $key => $value;
}
};
AryO\ArrayObject::registerMethod($noop, 'noop');
$object = new AryO\ArrayObject($whateverSource);
$object->noop();
foreach ($data as $key => $value) {
// ... whatever
}
This adds the new method ArrayObject::noop()
to the existing implementation of the
ArrayObject
to be used by every new instance.
Operator functions are meant to be pure functions. They need to accept a Traversable
as
the very first argument (chances are that's a Generator
but it can be an ArrayIterator
or any Iterator
or IteratorAggregate
as well) and they are required to return a
Traversable
, too.
Although registering operator methods by hand can be done, that's not the way it is intended
to. Instead, there's the AbstractOperator
class providing public static methods and a
registering method.
Define the operator:
<?PHP
use StephanSchuler\Demo;
use StephanSchuler\ArrayObject as AryO;
class MyOperator extends AryO\Operator\AbstractOperator
{
public static function noop(\Traversable $data): \Traversable
{
foreach ($data as $key => $value) {
yield $key => $value;
}
}
}
Register and use on runtime:
<?PHP
use StephanSchuler\Demo\MyOperator;
use StephanSchuler\ArrayObject as AryO;
MyOperator::register();
$data = new AryO\ArrayObject($whateverSource);
$data->noop();
foreach ($data as $key => $value) {
// ... whatever
}
There are a couple of operators implemented just the way explained in the last section:
<?PHP
use StephanSchuler\ArrayObject as AryO;
AryO\Operator\ChunkOperator::register();
AryO\Operator\CountOperator::register();
AryO\Operator\FilterOperator::register();
AryO\Operator\FlipOperator::register();
AryO\Operator\GroupOperator::register();
AryO\Operator\IntersectOperator::register();
AryO\Operator\MapOperator::register();
AryO\Operator\ReduceOperator::register();
AryO\Operator\SortOperator::register();
They are provide several methods each explained in individual documentation files.
Have a look at the folder stubs/Operator. For every build
in Operator class there is a file named alike containing a new class definition for
ArrayObject. They are not meant to be loaded ever because that would conflict with the
original ArrayObject
class definition. But thes do help IDEs like PHPStorm to auto
complete and type hint for every method available.