Skip to content

生成器(Generator)使用详解

生成器是 PHP 5.5+ 引入的特性,用于高效处理大数据集,避免内存溢出。

基本语法

使用 yield 关键字创建生成器:

php
function rangeGenerator($start, $end) {
    for ($i = $start; $i <= $end; $i++) {
        yield $i;
    }
}

// 使用
foreach (rangeGenerator(1, 1000000) as $number) {
    echo $number . "\n";
}

对比内存占用

php
// ❌ 内存占用高
$numbers = range(1, 1000000);  // 约 134MB
foreach ($numbers as $n) {
    // ...
}

// ✅ 生成器几乎不占内存
function bigRange($start, $end) {
    for ($i = $start; $i <= $end; $i++) {
        yield $i;
    }
}

foreach (bigRange(1, 1000000) as $n) {
    // 仅占用几KB
}

生成键值对

php
function keyValueGenerator() {
    yield 'id' => 1;
    yield 'name' => '张三';
    yield 'age' => 25;
}

foreach (keyValueGenerator() as $key => $value) {
    echo "$key: $value\n";
}

从生成器获取值

php
function gen() {
    yield 1;
    yield 2;
    yield 3;
}

$generator = gen();

echo $generator->current();  // 1
$generator->next();
echo $generator->current();  // 2

// 或使用 foreach
foreach ($generator as $value) {
    echo $value;
}

双向通信(PHP 7+)

php
function printer() {
    while (true) {
        $line = yield;
        echo "收到: $line\n";
    }
}

$printer = printer();
$printer->send("Hello");  // 收到: Hello
$printer->send("World");   // 收到: World

读取大文件

php
function readLargeFile($filename) {
    $handle = fopen($filename, 'r');
    while (!feof($handle)) {
        yield fgets($handle);
    }
    fclose($handle);
}

// 处理 GB 级文件只需几 MB 内存
foreach (readLargeFile('huge.log') as $line) {
    processLine($line);
}

yield from(PHP 7+)

委托给另一个生成器:

php
function subGenerator() {
    yield 1;
    yield 2;
}

function mainGenerator() {
    yield 'a';
    yield from subGenerator();
    yield 'b';
}

// 输出: a, 1, 2, b
foreach (mainGenerator() as $value) {
    echo $value;
}

注意事项

  1. 生成器不能 return 值(PHP 7 起可以 return
  2. 生成器是单向的,不能倒退
  3. 生成器对象不能被序列化

Binstork