CodeBlanks Logo Icon CodeBlanks

Summary - Generators

PHP course · Expert · Lesson 7/54

Build a large log file parser with yield, yield from and pipelines.

Summary - Generators

In this group you learned functions that yield values with yield, the methods of the Generator class, and memory savings. You saw infinite generators, delegation with yield from and pipelines.

Now combine everything: you will build a log parser. Yield lines with yield, delegate a sub-generator with yield from and set up a pipeline flow.

A log parsing pipeline

A log parser has two generators: logLines yields lines one by one, errorLines filters only those containing ERROR. This sets up a flow; no lines are loaded into memory.

A third generator allErrors delegates with yield from errorLines($lines). This combines both yield and yield from.

Exercise Write the logLines generator

Write logLines(array $lines): \Generator: yield each line in the $lines array. Iterate logLines($lines) with foreach and print each line on its own line.

Show example solution
In logLines, loop foreach ($lines as $line), yield $line;. Then iterate foreach (logLines($lines) as $line) and echo $line . "\n";
Example solution:
<?php
function logLines(array $lines): \Generator {
    foreach ($lines as $line) {
        yield $line;
    }
}

$lines = ["2025-01-01 INFO start", "2025-01-01 WARN slow", "2025-01-01 ERROR connection"];

foreach (logLines($lines) as $line) {
    echo $line . "\n";
}

Exercise Filter ERROR lines and delegate with yield from

Write errorLines(array $lines): \Generator: iterate logLines($lines) with foreach, use strpos to select lines containing ERROR and yield them. Write allErrors(array $lines): \Generator: delegate with yield from errorLines($lines). Iterate allErrors($lines) with foreach and print each line.

Show example solution
In errorLines, loop foreach (logLines($lines) as $line), if strpos($line, "ERROR") !== false yield $line;. In allErrors, yield from errorLines($lines);. Then iterate foreach (allErrors($lines) as $line) and echo $line . "\n";
Example solution:
<?php
function logLines(array $lines): \Generator {
    foreach ($lines as $line) {
        yield $line;
    }
}

function errorLines(array $lines): \Generator {
    foreach (logLines($lines) as $line) {
        if (strpos($line, "ERROR") !== false) {
            yield $line;
        }
    }
}

function allErrors(array $lines): \Generator {
    yield from errorLines($lines);
}

$lines = [
    "2025-01-01 INFO start",
    "2025-01-01 ERROR connection lost",
    "2025-01-01 WARN slow",
    "2025-01-01 ERROR disk full",
];

foreach (allErrors($lines) as $line) {
    echo $line . "\n";
}

Test yourself

  1. Which structure uses the least memory?

    • Build an array with range(1, 1000)
    • Load all lines into an array
    • Yield lines one by one with a generator
    • Hold all data in a variable
    Show answer

    Yield lines one by one with a generator — Correct. A generator holds one value at a time; it uses the least memory.

  2. allErrors delegates to errorLines

    function inner(): \Generator {
        yield 'a';
        yield 'b';
    }
    
    function outer(): \Generator {
        ____ inner();
        yield 'c';
    }
    
    Show answer
    function inner(): \Generator {
        yield 'a';
        yield 'b';
    }
    
    function outer(): \Generator {
        yield from inner();
        yield 'c';
    }
    

All lessons in Expert