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.