yield turns a 500 MB export into a stream

A method that builds an array of rows and returns it holds the entire result set in memory at once. A product export that was comfortable at 20,000 rows becomes a fatal error at 400,000, and raising memory_limit only changes the number at which it dies. Generators, new in 5.5, let the function produce rows one at a time without the caller knowing.

function exportRows(PDO $pdo)
{
    $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

    $stmt = $pdo->query('SELECT sku, name, price, stock FROM products');

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

$out = fopen('php://output', 'w');

foreach (exportRows($pdo) as $row) {
    fputcsv($out, $row);
}

Peak memory on that export dropped from 480 MB to under 3 MB, and the calling loop is unchanged — a generator is iterated exactly like an array. The unbuffered attribute is the half that gets forgotten: without it mysqlnd pulls the whole result set into PHP before the first fetch() returns, so the generator carefully streams something that is already entirely in memory. What it costs is that the sequence is one-way and single-use. You cannot count() it, cannot iterate it twice, and the connection stays occupied until the result set is drained, so no other query can run on that handle inside the loop.