The benefits of implementing ArrayAccess
is simple: You can access the whole object or just a very specific, even private
property as array.
In this very simple example, we use Iterator
and ArrayAccess
to have access to a specific property named $array
.
class Foo implements \ArrayAccess, \Iterator
{
public $pointer = 0;
private $array = [
'first value',
'second value',
'third value',
];
public function __construct()
{
$this->pointer = 0;
}
public function current()
{
return $this->array[ $this->pointer ];
}
public function key()
{
return $this->pointer;
}
public function next()
{
++$this->pointer;
}
public function rewind()
{
$this->pointer = 0;
}
public function valid()
{
return isset( $this->array[ $this->position ] );
}
}
We can now loop through it like we would loop through every array:
$foo = new Foo();
foreach ( $foo as $key => $value )
{
print "Index: {$key} - Value: {$value}".PHP_EOL;
}
As seen in the previous example, we need to implement all that methods just to loop trough and have access to already present data. And to implement ArrayAccess
, which allows us to actually set values, we'll have to implement another set of methods:
ArrayAccess {
abstract public boolean offsetExists ( mixed $offset )
abstract public mixed offsetGet ( mixed $offset )
abstract public void offsetSet ( mixed $offset , mixed $value )
abstract public void offsetUnset ( mixed $offset )
}
Now we can totally leave off writing and repeating that (current/key/next/etc) set of methods, by simply using IteratorAggregate
. This sums it into a single, mandatory method: getIterator()
.
Now we'd have a resulting class like this:
class Bar implements \ArrayAccess, \IteratorAggregate
{
private $array = [];
public function getIterator()
{
return new ArrayIterator( $this->array );
}
}
And we have full array access to the classes $array
property. We can set and unset values, check if they return isset
, can loop through them etc. Much more convenient. And it does exactly the same thing as all those eight methods above, just by implementing IteratorAggregate
.
A last note: You'll likely do one more step and implement Traversable
as well. This interface is very nice, as it allows you to make implementing either Iterator
or IteratorAggregate
mandatory without explicitly stating which one the implementing developer needs to use. It just explains that it is mandatory that the object has to be loopable.
$foo = new IteratorContainerController();
$foo->addDependency( Traversable $bar );
This means that the Dependency for IteratorContainerController()
will always be either an Iterator
or an IteratorAggregate
implemented object. So someone can simply throw an IteratorAggregate
in or, if s/he needs more fine grained control or does pre-processing of variables before they get set, s/he can simply use Iterator
.