← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Generators & yield

php PHP 5.5+ Intermediate
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list phpstan and rector as tools, and the code_pattern describes a specific anti-pattern (building $results[] in a loop then returning) that these tools can flag. This is not caught by the compiler or a default linter, but requires a specialist static analysis or refactoring tool to identify.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix says to replace functions that build and return large arrays with generators using yield. This is a localised refactor — converting a function's return pattern to yield — typically within one function or one file, but not a single one-line swap since iteration call sites and try/finally cleanup may need minor adjustment.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Applies to web, cli, and queue-worker contexts broadly, but the structural commitment is localised to the functions/components that consume large sequences. The rest of the codebase is unaffected. Callers do need to iterate rather than index into a collection, but this is a contained adaptation rather than a system-wide architectural constraint.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception field explicitly states that developers believe generators are 'just a fancy way to return arrays,' when in fact they are lazy and single-use. Common mistakes reinforce this: forgetting forward-only/single-use nature, misunderstanding when side effects run (yield pauses execution), and confusing return vs yield semantics. These are documented gotchas that most developers learn through experience, placing this squarely at t5.

About DEBT scoring →

Also Known As

PHP generators yield lazy iteration

TL;DR

Generators allow iterating over large datasets lazily using yield, without loading everything into memory at once.

Explanation

A generator function uses yield to produce values one at a time, pausing execution between yields. The caller receives a Generator object implementing the Iterator interface. This enables processing of large files, database result sets, or infinite sequences with O(1) memory usage rather than O(n). yield from enables delegation to another generator or iterable. Generators also support bidirectional communication — callers can send values back to the generator via Generator::send().

Diagram

flowchart LR
    CALL2[Call generator function] --> ITER2[Returns Generator object<br/>body NOT executed]
    ITER2 -->|foreach or next| RUN[Execute until yield]
    RUN -->|yield value| SUSPENDED[Suspended<br/>value returned to caller]
    SUSPENDED -->|next iteration| RUN
    RUN -->|function ends| COMPLETE[Generator complete<br/>valid = false]
    subgraph Memory_Benefit
        EAGER[range 1 1000000<br/>builds full array in memory]
        LAZY[xrange generator<br/>one value at a time]
        EAGER --> MEM_BAD[400MB RAM]
        LAZY --> MEM_GOOD[Constant memory]
    end
style SUSPENDED fill:#6e40c9,color:#fff
style MEM_BAD fill:#f85149,color:#fff
style MEM_GOOD fill:#238636,color:#fff

Common Misconception

Generators are just a fancy way to return arrays. Generators produce values lazily — each value is computed only when requested. Processing a 10-million-row dataset with a generator uses constant memory; building the same array first exhausts memory.

Why It Matters

Generators process sequences lazily — they yield one item at a time rather than building the entire collection in memory. For large datasets (CSV exports, database cursors, log streams) they are the difference between 10 MB memory usage and an out-of-memory crash.

Common Mistakes

  • Using a generator where you need to rewind or count — generators are forward-only and single-use.
  • Forgetting that yield pauses execution — side effects before yield do not run until the generator is iterated.
  • Returning a value from a generator with return instead of yield — it sets the return value, not a yielded item.
  • Not wrapping database cursor generators in try/finally to ensure the connection is closed on early exit.

Code Examples

✗ Vulnerable
// Loading all rows into memory:
function getAllUsers(): array {
    return $this->db->query('SELECT * FROM users')->fetchAll(); // 1M rows in RAM
}

// Generator — yields one at a time:
function streamUsers(): Generator {
    $stmt = $this->db->query('SELECT * FROM users');
    while ($row = $stmt->fetch()) yield $row;
}
✓ Fixed
// Process large CSV without loading it all into memory
function readCsv(string $path): Generator {
    $fp = fopen($path, 'r');
    try {
        while (($row = fgetcsv($fp)) !== false) {
            yield $row;
        }
    } finally {
        fclose($fp);
    }
}

foreach (readCsv('million_rows.csv') as $row) {
    processRow($row); // constant memory — one row at a time
}

// Infinite sequence
function fibonacci(): Generator {
    [$a, $b] = [0, 1];
    while (true) {
        yield $a;
        [$a, $b] = [$b, $a + $b];
    }
}
$fib = fibonacci();
echo $fib->current(); // 0
$fib->next();
echo $fib->current(); // 1

Added 15 Mar 2026
Edited 22 Mar 2026
Views 36
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 2 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 1 ping S 1 ping S 1 ping M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S
No pings yet today
Perplexity 9 Amazonbot 7 Ahrefs 7 Unknown AI 2 SEMrush 2 Majestic 1 ChatGPT 1 Google 1
crawler 30
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Replace functions that build and return large arrays with generators using yield — memory stays constant regardless of dataset size
📦 Applies To
PHP 5.5+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Function building $results = [] then appending in loop and returning — candidate for yield
Auto-detectable: ✓ Yes phpstan rector
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update

✓ schema.org compliant