PHP|PHP實踐-生成器

PHP生成器是5.5.0引入的功能。php

生成器實際上就是簡單的迭代器。函數

與標準的PHP迭代器不一樣,生成器不要求類實現Iterator接口,從而減輕了類的負擔。性能

生成器會根據需求計算產出迭代的值。而標準的PHP迭代器常常在內存中執行迭代操做,這要預先計算出數據集,性能較低。.net

若是使用特定的防禦計算大量數據,能夠使用生成器,即時計算併產出後續值,不佔用內存。code

生成器不能完成全部迭代器的操做。沒法後退,快進,而且生成器是一次性的,沒法對此迭代同一個生成器。對象

建立

生成器從不返回值,只是產出值。接口

<?php

function myGenerator() {
    yield 'v1';
    yield 'v2';
    yield 'v3';
}

調用生成器函數時,PHP會反悔一個屬於Generator類的對象。這個對象是能夠foreach迭代的。每次迭代,PHP要求這個實例計算並提供下一個要迭代的值。內存

每次產出一個值,生成器的內部狀態都會停頓。向生成器請求下一個值時,內部狀態纔會恢復。這種停頓-恢復的狀態會一直持續下去。get

<?php
foreach (myGenerator() as $yieldValue) {
    echo $yieldValue , PHP_EOL;
}

使用

<?php

function makeRange($length) {
    $dataset = [];
    for ($i = 0; $i < $length; $i++) {
        $dataset[] = $i;
    }
    
    return $dataset;
}

$customRange = makeRange(1000000);
foreach ($customRange as $i) {
    echo $i, PHP_EOL;
}

上面的這個方法並無善用內存,使用生成器只會爲一個整數分配內存。it

<?php
function makeRange($length) {
    for ($i = 0; $i < $length; $i++) {
        yield $i;
    }
}

foreach(makeRange(1000000) as $i) {
    echo $i, PHP_EOL;
}

再舉個例子:使用生成器處理CSV文件

<?php
function getRows($file) {
    $handle = fopen($file, 'rb');
    if ($handle === false) {
        throw new Exception();
    }
    
    while (feof($handle) === false) {
        yield fgetcsv($handle);
    }
    fclose($handle);
}

foreach (getRows('data.csv') as $row) {
    print_r($row);
}

這個例子中,生成器只會爲CSV文件分配一行內存,而不是讀入整個文件到內存。

若是須要更多功能,例如在數據集中執行後腿,快進或查找操做,最好本身編寫類,實現Iterator接口(http://php.net/manual/class.iterator.php),或者使用PHP標準庫中某個原生的迭代器(http://php.net/manual/spl.iterators.php)

參考:

  1. Modern PHP

  2. http://bit.ly/ircmaxwell

相關文章
相關標籤/搜索