Last active
October 11, 2023 15:05
-
-
Save athrawes/e451484fdb4d0646f9aa03c9e47b566a to your computer and use it in GitHub Desktop.
Demonstrates an issue with `\iter\isEmpty()` for objects implementing `\IteratorAggregate` where `getIterator()` is impure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Copied directly from https://github.com/nikic/iter/blob/master/src/iter.php#L1090 | |
* on commit d9f88bc | |
*/ | |
function isEmpty($iterable): bool { | |
if (\is_array($iterable) || $iterable instanceof \Countable) { | |
return count($iterable) == 0; | |
} | |
if ($iterable instanceof \Iterator) { | |
return !$iterable->valid(); | |
} else if ($iterable instanceof \IteratorAggregate) { | |
$inner = $iterable->getIterator(); | |
if ($inner instanceof \Iterator) { | |
return !$inner->valid(); | |
} else if ($inner !== $iterable) { | |
return isEmpty($inner); | |
} else { | |
throw new \InvalidArgumentException( | |
'Argument must not be recursively defined'); | |
} | |
} else { | |
throw new \InvalidArgumentException( | |
'Argument must be iterable or implement Countable'); | |
} | |
} | |
class MyIter implements \IteratorAggregate | |
{ | |
/** | |
* Simulates some stateful generator which cannot be safely restarted | |
* or rewound | |
*/ | |
private array $inner; | |
public function __construct() { | |
$this->inner = [1, 2, 3, 4, 5]; | |
} | |
public function getIterator(): \Traversable | |
{ | |
while (!empty($this->inner)) { | |
yield array_shift($this->inner); | |
} | |
} | |
} | |
$gen = new MyIter(); | |
echo "gen isEmpty? " . (isEmpty($gen) ? "yes" : "no") . "\n"; | |
// prints: no | |
foreach ($gen as $value) { | |
echo "got $value\n"; | |
} | |
// prints: | |
// | |
// > got 2 | |
// > got 3 | |
// > got 4 | |
// > got 5 | |
// | |
// instead of expected | |
// | |
// > got 1 | |
// > got 2 | |
// > got 3 | |
// > got 4 | |
// > got 5 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment