生成器和数组有什么区别?

Dav*_*ues 37 php arrays iterator generator

今天PHP团队发布了PHP 5.5.0版本,其中包括对生成器的支持.阅读文档,我注意到它完全可以用数组做.

PHP团队生成器示例:

// Only PHP 5.5
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        // Note that $i is preserved between yields.
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}
Run Code Online (Sandbox Code Playgroud)

结果:

1
2
3
Run Code Online (Sandbox Code Playgroud)

但我可以使用数组做同样的事情.我仍然可以保持与早期版本的PHP兼容.

看看:

// Compatible with 4.4.9!
function gen_one_to_three() {
    $results = array();
    for ($i = 1; $i <= 3; $i++) {
        $results[] = $i;
    }

    return $results;
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}
Run Code Online (Sandbox Code Playgroud)

所以问题是:这个新功能的存在目的什么?我必须在不使用新功能的情况下播放所有文档示例,将其替换为数组.

任何人都可以给出一个很好的解释,也许是旧版本不一定不可能的例子,但使用生成器可以帮助开发吗?

irc*_*ell 59

不同之处在于效率.例如,PHP以外的许多语言包括两个range函数,range()xrange().这是生成器的一个很好的例子,以及为什么要使用它们.让我们建立自己的:

function range($start, $end) {
    $array = array();
    for ($i = $start; $i <= $end; $i++) {
        $array[] = $i;
    }
    return $array;
}
Run Code Online (Sandbox Code Playgroud)

现在,这真的很直接.但是,对于大范围,它需要大量的内存.如果我们尝试用$start = 0和运行它$end = 100000000,我们可能会耗尽内存!

但如果我们使用发电机:

function xrange($start, $end) {
    for ($i = $start; $i <= $end; $i++) {
        yield $i;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们使用常量内存,但仍然有一个"数组"(比如结构),我们可以在同一个空间中迭代(并与其他迭代器一起使用).

它不会取代数组,但它确实提供了避免需要内存的有效方法......

但它也可以节省物品的生成.由于每个结果都是根据需要生成的,因此您可以延迟执行(获取或计算)每个元素,直到您需要它为止.因此,例如,如果您需要从数据库中获取项目并对每行执行一些复杂的处理,则可以使用生成器延迟该项,直到您实际需要该行为止:

function fetchFromDb($result) {
    while ($row = $result->fetchArray()) {
        $record = doSomeComplexProcessing($row);
        yield $record;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您只需要前3个结果,则只需处理前三个记录.

有关更多信息,我写了一篇关于这个主题的博客文章.


Tim*_*lla 13

生成器允许对复杂语句进行惰性求值.这样就可以节省内存,因为您不必一次分配所有内容.

除了可迭代之外,它们几乎不相同.An array是数据结构,生成器不是.


Mar*_*ker 11

在开始循环之前,数组必须包含您循环的每个值; 生成器根据请求"动态"创建每个值,因此内存更少;

数组使用它包含的值,并且必须预先填充这些值; 生成器可以根据直接使用的特殊标准创建值...例如,斐波纳西序列,或来自非AZ字母表的字母(通过UTF-8数值计算)有效地允许alphaRange('א','ת' );

编辑

function fibonacci($count) {
    $prev = 0;
    $current = 1;

    for ($i = 0; $i < $count; ++$i) {
        yield $prev;
        $next = $prev + $current;
        $prev = $current;
        $current = $next;
    }
}

foreach (fibonacci(48) as $i => $value) {
    echo $i , ' -> ' , $value, PHP_EOL;
}
Run Code Online (Sandbox Code Playgroud)

编辑

只是为了好玩,这是一个将希伯来字母作为UTF-8字符返回的生成器

function hebrewAlphabet() {
    $utf8firstCharacter = 1488;
    $utf8lastCharacter = 1514;
    for ($character = $utf8firstCharacter; $character <= $utf8lastCharacter; ++$character) {
        yield html_entity_decode('&#'.$character.';', ENT_NOQUOTES, 'UTF-8');
    };
}

foreach(hebrewAlphabet() as $character) {
    echo $character, ' ';
}
Run Code Online (Sandbox Code Playgroud)