(PHP 5, PHP 7, PHP 8)
Interface to create an external Iterator.
Example #1 Basic usage
<?php
class myData implements IteratorAggregate
{
public function getIterator(): Traversable
{
return new ArrayIterator([
"key one" => "item one",
"key two" => "item two",
"key three" => "item three"
]);
}
}
$obj = new myData();
foreach ($obj as $key => $value) {
var_dump($key, $value);
echo "\n";
}The above example will output something similar to:
string(7) "key one" string(8) "item one" string(7) "key two" string(8) "item two" string(9) "key three" string(10) "item three"
It might seem obvious, but you can return a compiled generator from your IteratorAggregate::getIterator() implementation.
<?php
class Collection implements IteratorAggregate
{
private $items = [];
public function __construct($items = [])
{
$this->items = $items;
}
public function getIterator()
{
return (function () {
while(list($key, $val) = each($this->items)) {
yield $key => $val;
}
})();
}
}
$data = [ 'A', 'B', 'C', 'D' ];
$collection = new Collection($data);
foreach ($collection as $key => $val) {
echo sprintf("[%s] => %s\n", $key, $val);
}
?>Note that, at least as of 5.3, you still aren't allowed to return a normal Array from getIterator().
In some places, the docs wrap the array into an ArrayObject and return that. DON'T DO IT. ArrayObject drops any empty-string keys on the floor when you iterate over it (again, at least as of 5.3).
Use ArrayIterator instead. I wouldn't be surprised if it didn't have its own set of wonderful bugs, but at the very least it works correctly when you use it with this method.You can use yield from in getIterator in recent PHP 7 versions:
<?php
class Example implements \IteratorAggregate
{
protected $data = [];
public function __construct(array $data)
{
$this->data = $data;
}
public function getIterator()
{
yield from $this->data;
}
}
$test = new Example([1, 2, 3]);
foreach ($test as $node) {
echo $test, PHP_EOL;
}
/*
* Outputs:
*
* 1
* 2
* 3
*/ ?><?php
// IteratorAggregate
// Create indexed and associative arrays.
class myData implements IteratorAggregate {
private $array = [];
const TYPE_INDEXED = 1;
const TYPE_ASSOCIATIVE = 2;
public function __construct( array $data, $type = self::TYPE_INDEXED ) {
reset($data);
while( list($k, $v) = each($data) ) {
$type == self::TYPE_INDEXED ?
$this->array[] = $v :
$this->array[$k] = $v;
}
}
public function getIterator() {
return new ArrayIterator($this->array);
}
}
$obj = new myData(['one'=>'php','javascript','three'=>'c#','java',], /*TYPE 1 or 2*/ );
foreach($obj as $key => $value) {
var_dump($key, $value);
echo PHP_EOL;
}
// if TYPE == 1
#int(0)
#string(3) "php"
#int(1)
#string(10) "javascript"
#int(2)
#string(2) "c#"
#int(3)
#string(4) "java"
// if TYPE == 2
#string(3) "one"
#string(3) "php"
#int(0)
#string(10) "javascript"
#string(5) "three"
#string(2) "c#"
#int(1)
#string(4) "java"
?>
Good luck!With PHP 8.5, using an object as a backing array for ArrayIterator is deprecated, as it allows violating class constraints and invariants. This means the example code above no longer functions. Luckily, there is an easy fix that only requires changing the return statement in the getIterator method. Below are two options for achieving the same functionality:
<?php
public function getIterator(): Traversable
{
return new ArrayIterator(get_object_vars($this));
}
?>
OR
<?php
public function getIterator(): Traversable
{
yield from get_object_vars($this);
}
?>