← Tilbage til koncepter

Generators & Iterators

Memory-effektiv iteration med yield keyword, generator functions og generator delegation i PHP

Kategori: Fundamentals

🎯 Key Points

  • yield keyword - Producerer værdier én ad gangen i stedet for at returnere hele array
  • Memory efficiency - Kun én værdi i memory ad gangen, perfekt til store datasæt
  • Lazy evaluation - Værdier genereres on-demand når de anmodes
  • Generator delegation (yield from) - Delegér iteration til anden generator eller iterable
  • send() method - Send værdier tilbage til generator under iteration
  • Generator return values - Returnér final value efter iteration er færdig
  • Iterator interface - Generators implementerer automatisk Iterator interface
  • Bidirectional communication - To-vejs kommunikation mellem caller og generator
  • Infinite sequences - Generér uendelige sekvenser uden memory issues
  • File processing - Læs store filer linje for linje uden at loade alt i memory
  • throw() method - Kast exceptions ind i generator for error handling
  • State preservation - Generator bevarer state mellem yield calls

💻 Kode Eksempel

<?php

// Basic generator for range
function generateRange(int $start, int $end, int $step = 1): Generator {
    for ($i = $start; $i <= $end; $i += $step) {
        yield $i;
    }
}

// Generator for reading large files line by line
function readLargeFile(string $filename): Generator {
    $handle = fopen($filename, 'r');
    
    if (!$handle) {
        throw new RuntimeException("Cannot open file: {$filename}");
    }
    
    try {
        while (($line = fgets($handle)) !== false) {
            yield trim($line);
        }
    } finally {
        fclose($handle);
    }
}

// Generator delegation with yield from
function generateAlphabet(): Generator {
    yield from range('a', 'z');
}

function generateAlphaNumeric(): Generator {
    yield from generateAlphabet();
    yield from range(0, 9);
}

// Generator with send() for bidirectional communication
function logger(): Generator {
    $logLevel = 'INFO';
    
    while (true) {
        $message = yield;
        echo "[{$logLevel}] {$message}\n";
        
        // Check if new log level was sent
        $newLevel = yield;
        if ($newLevel !== null) {
            $logLevel = $newLevel;
        }
    }
}

// Generator with return value
function processData(array $data): Generator {
    $sum = 0;
    
    foreach ($data as $item) {
        $sum += $item;
        yield $item * 2;
    }
    
    return $sum; // Return value after iteration
}

// Usage examples
echo "=== Range Generator ===\n";
foreach (generateRange(1, 5) as $num) {
    echo "Number: {$num}\n";
}

echo "\n=== Generator Delegation ===\n";
$count = 0;
foreach (generateAlphaNumeric() as $char) {
    echo $char . " ";
    if (++$count % 10 === 0) echo "\n";
}

echo "\n\n=== Generator with Return ===\n";
$gen = processData([1, 2, 3, 4, 5]);
foreach ($gen as $value) {
    echo "Processed: {$value}\n";
}
echo "Sum: {$gen->getReturn()}\n";

💼 Hvornår bruges det?

  • Læsning af store log filer eller CSV filer linje for linje uden at loade hele filen i memory
  • Database result pagination hvor kun current page's rows er i memory ad gangen
  • API response streaming hvor data sendes til klient i chunks i stedet for at vente på komplet response
  • Fibonacci sequences og andre matematiske serier der kan være uendelige eller meget store
  • ETL processes hvor data transformeres on-the-fly under iteration uden intermediate storage
  • Async operations i ReactPHP eller Amphp hvor generators bruges til coroutines og concurrent tasks

⭐ Best Practices

  • Brug generators til store datasæt - hvis array er > 10,000 items eller > 1MB, overvej generator
  • Kombiner yield from for at delegere til andre generators eller iterables for bedre composition
  • Brug finally blocks når generators arbejder med resources (files, connections) for proper cleanup
  • Type hint return type som Generator for bedre IDE support og documentation
  • Undgå kompleks state management i generators - hold dem simple og fokuserede
  • Brug generator return values til at kommunikere summary statistics efter iteration
  • Test generators med iterator_to_array() i unit tests, men vær opmærksom på memory usage
  • Dokumentér hvad generator yielder (key/value types) med @return Generator<key, value> PHPDoc

ℹ️ Quick Info

Kategori
Fundamentals
Sværhedsgrad
Mellem til Avanceret