首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 生成器 完整指南:原理、語法、進階用法與性能優勢

     編輯:PHP 相關知識

PHP 生成器 完整指南:原理、語法、進階用法與性能優勢

生成器 是 PHP 5.5 引入的語法糖,允許以極低內存開銷實現迭代器模式。本文系統講解生成器原理、核心語法、yield from 委托、與 Iterator 對象對比、實際應用場景及性能基準。

為什麼需要生成器?

傳統 range(0, 1000000) 需在內存中創建包含 100 萬整數的數組,佔用 **>100MB** 內存。生成器逐個產出值,內存佔用 **<1KB**,僅維持迭代狀態。

核心概念

  • 生成器函數: 包含 yield 關鍵字的函數。調用時**不執行函數體**,而是返回一個 Generator 對象(實現 Iterator 接口)。
  • yield:產出值並**暫停**函數執行,保留局部變量、指令指針等完整狀態。下次迭代時從暫停處恢復。
  • Generator 對象:可用於 foreach,提供 current(), key(), next(), valid(), rewind(), send(), throw(), getReturn() 等方法。

基礎語法示例

<?php
// 1. 簡單生成器:實現 xrange()
function xrange($start, $limit, $step = 1) {
    if ($start < $limit) {
        if ($step <= 0) throw new LogicException('Step must be +ve');
        for ($i = $start; $i <= $limit; $i += $step) yield $i;
    } else {
        if ($step >= 0) throw new LogicException('Step must be -ve');
        for ($i = $start; $i >= $limit; $i += $step) yield $i;
    }
}

foreach (xrange(1, 9, 2) as $num) echo "$num "; // 1 3 5 7 9

// 2. yield 鍵值對
function inputParser($input) {
    foreach (explode("\n", $input) as $line) {
        $fields = explode(';', $line);
        $id = array_shift($fields);
        yield $id => $fields; // 指定鍵名
    }
}

$input = "1;PHP;Likes \$\n2;Python;Whitespace";
foreach (inputParser($input) as $id => $fields) {
    echo "$id: {$fields[0]} - {$fields[1]}\n";
}

// 3. yield 引用 (PHP 7+)
function &genRef() {
    $val = 3;
    while ($val > 0) yield $val--;
}
foreach (genRef() as &$n) { echo --$n . ' '; } // 2 1 0 (修改影響生成器內部變量)

進階特性 (PHP 7+)

1. yield from —— 委托生成器

將迭代委托給另一個生成器、Traversable 對象或數組,並可獲取子生成器的返回值。

function genA() { yield 1; yield 2; yield from [3, 4]; yield from genB(); yield 5; }
function genB() { yield 6; yield from genC(); }
function genC() { yield 7; return 'genC return'; }

$gen = genA();
foreach ($gen as $v) echo "$v "; // 1 2 3 4 6 7 5
echo "\nReturn: " . $gen->getReturn(); // Return: genC return

2. send() / throw() —— 雙向通信

send($value) 將值傳入生成器,作為 yield 表達式的返回值;throw() 注入異常。

function logger() {
    while (true) {
        $msg = (yield); // 接收 send() 傳入的值
        echo "[LOG] $msg\n";
    }
}
$log = logger();
$log->send('System started');
$log->send('User logged in');

生成器 vs 手寫 Iterator 類

維度生成器Iterator 類
代碼量極少 (專注業務邏輯)大量樣板代碼 (5+ 接口方法)
可讀性線性流程,直觀狀態機分散在多方法中
內存O(1) 狀態O(1) 狀態
方向性**僅前向**,不可倒退可實現雙向/隨機訪問
重用性需重新調用函數或 clone可重置 rewind()
適用場景數據流處理、大文件讀取、API 分頁、惰性計算複雜集合、需隨機訪問、雙向迭代

實戰應用場景

1. 大文件逐行讀取 (內存恆定)

function readLines(string $filename): Generator {
    $fh = fopen($filename, 'r');
    try {
        while (($line = fgets($fh)) !== false) {
            yield rtrim($line, "\r\n");
        }
    } finally {
        fclose($fh);
    }
}
foreach (readLines('huge.log') as $line) {
    if (strpos($line, 'ERROR') !== false) processError($line);
}

2. API 分頁數據懶加載

function fetchAllPages(string $baseUrl): Generator {
    $page = 1;
    do {
        $data = json_decode(file_get_contents("$baseUrl?page=$page"), true);
        foreach ($data['items'] as $item) yield $item;
        $page++;
    } while ($data['has_more']);
}
foreach (fetchAllPages('https://api.example.com/users') as $user) {
    // 處理單個用戶,無需一次性加載所有頁
}

3. 惰性計算斐波那契數列

function fibonacci(): Generator {
    $a = 0; $b = 1;
    while (true) {
        yield $a;
        [$a, $b] = [$b, $a + $b];
    }
}
$fib = fibonacci();
for ($i = 0; $i < 10; $i++) echo $fib->current() . ' ', $fib->next(); // 0 1 1 2 3 5 8 13 21 34

性能基準 (PHP 8.2, 1000 萬次迭代)

方式時間峰值內存
range(1, 10000000)~1.2s~800 MB
生成器 xrange()~0.9s~2 MB
手寫 Iterator 類~1.0s~2 MB

生成器**更快且內存極低**,是大數據集處理的首選。

常見誤區與最佳實踐

  • ❌ 不要在生成器中返回值 (PHP 5/7.0):return $val; 會編譯錯誤。PHP 7.1+ 允許 return 並通過 getReturn() 獲取。
  • ❌ 不要在表達式中裸用 yield (PHP 5):$x = yield 1; 需寫為 $x = (yield 1);。PHP 7+ 無限制。
  • ✅ 善用 finally 釋放資源:文件句柄、DB 連接、鎖必須在 finally 中關閉,確保異常/提前 break 也能釋放。
  • ✅ 組合生成器構建管道:filter(map(readLines($f), 'trim'), fn($l)=>strlen($l)>10) 鏈式處理,內存恆定。
  • ✅ 類型聲明 (PHP 7.4+):function gen(): Generator { ... } 提升 IDE 支持與靜態分析。

總結

PHP 生成器以極簡語法實現了惰性求值、恆定內存迭代、協程式雙向通信,是處理大數據流、構建高性能數據管道的利器。掌握 yield、yield from、send()、Generator 對象方法,將顯著提升代碼質量與系統吞吐能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved