iterable is not countable, and count() is a fatal

iterable accepts an array or a Traversable, and only one of those can be counted without consuming it.

function summarise(iterable $rows): string
{
    return count($rows) . ' rows';   // TypeError on a generator
}

// the options, all of which are a decision:
is_array($rows) ? count($rows) : iterator_count($rows);
// — iterator_count CONSUMES a generator. it is now empty.

// or narrow the parameter and make the caller decide:
function summarise(Countable&Traversable $rows): string

A generator has no length until it has finished, which is not an implementation gap but the point of it. Any function typed iterable that needs the count is really asking for an array and should say so; the ones that genuinely stream should count as they go. iterator_count is the trap, because it appears to solve the problem and silently exhausts the generator, so the next loop sees nothing.