The following code is equivalent:
function for_(Iterator $i): void
{
for ($i->rewind(); $i->valid(); $i->next()) {
$i->current();
$i->key();
}
}
Here is how I tested:
class IteratorTest extends TestCase
{
/**
* @dataProvider provide
*/
public function testDoesTheSameWithIterator(
Iterator $i,
callable $expectedFn,
callable $actualFn
): void {
$expectedI = new Iterator_($i);
$actualI = new Iterator_($i);
$expectedFn($expectedI);
$actualFn($actualI);
var_export($expectedI->calls);
self::assertSame($expectedI->calls, $actualI->calls);
}
public function provide(): array
{
return [
'for iterator vs foreach' => [
new ArrayIterator(['a' => 1, 2 => 'b', 3 => null]),
__NAMESPACE__ . 'foreach_',
__NAMESPACE__ . 'for_',
],
];
}
}
class Iterator_ implements Iterator
{
public array $calls = [];
private Iterator $i;
public function __construct(Iterator $i)
{
$this->i = $i;
}
public function __call($method, $arguments)
{
$return = $this->i->$method(...$arguments);
$this->calls[] = compact('method', 'arguments', 'return');
return $return;
}
public function current()
{
return $this->__call(__FUNCTION__, func_get_args());
}
public function next(): void
{
$this->__call(__FUNCTION__, func_get_args());
}
public function key()
{
return $this->__call(__FUNCTION__, func_get_args());
}
public function valid(): bool
{
return $this->__call(__FUNCTION__, func_get_args());
}
public function rewind(): void
{
$this->__call(__FUNCTION__, func_get_args());
}
}
Here's what the test outputs:
array (
0 =>
array (
'method' => 'rewind',
'arguments' =>
array (
),
'return' => NULL,
),
1 =>
array (
'method' => 'valid',
'arguments' =>
array (
),
'return' => true,
),
2 =>
array (
'method' => 'current',
'arguments' =>
array (
),
'return' => 1,
),
3 =>
array (
'method' => 'key',
'arguments' =>
array (
),
'return' => 'a',
),
4 =>
array (
'method' => 'next',
'arguments' =>
array (
),
'return' => NULL,
),
5 =>
array (
'method' => 'valid',
'arguments' =>
array (
),
'return' => true,
),
6 =>
array (
'method' => 'current',
'arguments' =>
array (
),
'return' => 'b',
),
7 =>
array (
'method' => 'key',
'arguments' =>
array (
),
'return' => 2,
),
8 =>
array (
'method' => 'next',
'arguments' =>
array (
),
'return' => NULL,
),
9 =>
array (
'method' => 'valid',
'arguments' =>
array (
),
'return' => true,
),
10 =>
array (
'method' => 'current',
'arguments' =>
array (
),
'return' => NULL,
),
11 =>
array (
'method' => 'key',
'arguments' =>
array (
),
'return' => 3,
),
12 =>
array (
'method' => 'next',
'arguments' =>
array (
),
'return' => NULL,
),
13 =>
array (
'method' => 'valid',
'arguments' =>
array (
),
'return' => false,
),
)