Generators are one-shot and rewind throws

A generator can be iterated once, and the second foreach over the same instance throws rather than returning nothing.

$rows = readCsv($path);

foreach ($rows as $r) { /* ... */ }
foreach ($rows as $r) { /* ... */ }
// Exception: Cannot traverse an already closed generator

// and rewinding after the first yield:
$g = gen();
$g->current();
$g->next();
$g->rewind();   // Exception: Cannot rewind a generator
                // that was already run

Returning a generator from a method is therefore a contract that the caller will use it once, and that is not visible in the return type — iterable and Generator both look reusable. Returning a closure that produces a fresh generator is the fix when reuse is genuinely needed, and it makes the cost explicit. The exception is at least loud; the version of this bug that hurts is a generator passed to two collaborators, one of which silently sees an empty sequence.