Generators keep a million-row export inside memory

A method that builds an array and returns it holds every row in memory at once. For an export of a few hundred rows that is invisible; for a million it is a fatal error, and raising memory_limit only moves the failure further out.

function rows(PDOStatement $stmt)
{
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        yield $row;
    }
}

foreach (rows($stmt) as $row) {
    fputcsv($out, $row);
}

The calling code does not change: a generator is iterated exactly like an array. What changes is that only one row exists at a time. The cost is that you cannot count() the result or iterate it twice — if you need either, you needed the array after all, and it is better to discover that at the call site than in production.