首页 >后端开发 >php教程 >PHP主| PHP中的发电机

PHP主| PHP中的发电机

Lisa Kudrow
Lisa Kudrow原创
2025-02-23 09:12:11606浏览

PHP Master | Generators in PHP

核心要点

  • PHP生成器提供了一种简便的方法来实现迭代器,无需复杂的Iterator接口,而是使用yield关键字代替return来保存其状态,并在再次调用时从中断处继续。
  • 在处理大型数据集时,生成器非常节省内存,因为它们只需要为当前结果分配内存,而不需要像数组那样一次性将所有值存储在内存中。
  • 尽管生成器像迭代器一样工作,但它本质上是一个函数,可以通过调用生成器对象的send()方法来返回值和接收外部值。它还可以用于另一个生成器中,这被称为生成器委托。

如果您关注过我之前关于迭代器的文章,您就会知道迭代是一个重要的编程概念,但是实现创建可迭代对象的必要接口充其量是一件麻烦事,因为需要大量的样板代码。随着PHP 5.5的发布,我们终于有了生成器!在本文中,我们将了解生成器,它提供了一种简单的方法来实现简单的迭代器,而无需Iterator接口的开销或复杂性。

生成器的工作原理

根据维基百科的定义,生成器“非常类似于返回数组的函数,因为生成器具有参数,可以被调用,并生成一系列值”。生成器基本上是一个普通的函数,但它不是返回值,而是根据需要产生任意多个值。它看起来像一个函数,但行为像一个迭代器。生成器使用yield关键字代替return。它的作用类似于return,因为它将值返回给函数的调用者,但是yield不会将函数从堆栈中移除,而是保存其状态。这允许函数从中断处继续执行。事实上,您不能从生成器中返回值,尽管您可以使用不带值的return来终止其执行。PHP手册指出:“当调用生成器函数时,它会返回一个可以迭代的对象。”这是一个内部Generator类的对象,它以与仅向前迭代器对象相同的方式实现Iterator接口。当您迭代该对象时,PHP每次需要一个值时都会调用生成器。当生成器产生值时,状态会被保存,以便在需要下一个值时可以恢复。

<code class="language-php"><?php
function nums() {
    echo "The generator has started\n";
    for ($i = 0; $i < 5; $i++) {
        yield $i;
        echo "Yielded $i\n";
    }
    echo "The generator has ended\n";
}

foreach (nums() as $v);
?></code>

上述代码的输出将是:

<code>The generator has started
Yielded 0
Yielded 1
Yielded 2
Yielded 3
Yielded 4
The generator has ended</code>

我们的第一个生成器

生成器并非一个新概念,它已经存在于C#、Python、JavaScript和Ruby(枚举器)等语言中,通常通过使用yield关键字来识别。以下是一个Python示例:

<code class="language-python">def file_lines(filename):
    file = open(filename)
    for line in file:
        yield line
    file.close()

for line in file_lines('somefile'):
    #do some work here</code>

让我们用PHP重写Python生成器示例。(请注意,这两个代码片段都没有执行任何错误检查。)

<code class="language-php"><?php
function nums() {
    echo "The generator has started\n";
    for ($i = 0; $i < 5; $i++) {
        yield $i;
        echo "Yielded $i\n";
    }
    echo "The generator has ended\n";
}

foreach (nums() as $v);
?></code>

生成器函数打开一个文件,然后根据需要产生文件的每一行。每次调用生成器时,它都会从中断处继续执行。它不会从头开始,因为当执行yield语句时,它的状态已被保存。一旦所有行都被读取,生成器就会简单地终止,循环结束。

返回键

PHP迭代器由键/值对组成。在我们的示例中,只返回了一个值,因此键是数字(默认情况下键是数字)。如果您希望返回一个关联对,只需更改yield语句以使用数组语法包含键即可。

<code>The generator has started
Yielded 0
Yielded 1
Yielded 2
Yielded 3
Yielded 4
The generator has ended</code>

注入值

yield不仅返回值;它还可以接收外部的值。这是通过使用您希望传递的值调用生成器对象的send()方法来完成的。然后,该值可用于计算或执行其他操作。该方法将值作为yield表达式的结果发送到生成器,并恢复执行。

<code class="language-python">def file_lines(filename):
    file = open(filename)
    for line in file:
        yield line
    file.close()

for line in file_lines('somefile'):
    #do some work here</code>

输出将是:

<code class="language-php"><?php
function file_lines($filename) {
    $file = fopen($filename, 'r');
    while (($line = fgets($file)) !== false) {
        yield $line;
    }
    fclose($file);
}

foreach (file_lines('somefile') as $line) {
    // do some work here
}
?></code>

使用生成器节省内存

当您计算大型集合并且不想同时为所有结果分配内存,或者当您不知道是否需要所有结果时,生成器非常有用。由于结果的处理方式,通过仅为当前结果分配内存,可以将内存占用量减少到非常低的水平。想象一下file()函数,它将文件中的所有行作为数组返回。对file()函数和我们的演示file_lines()函数运行一个简单的基准测试,每个函数都使用使用Lipsum生成的相同的随机100段文本文件,结果显示file函数使用的内存最多是生成器的110倍。

<code class="language-php"><?php
function file_lines($filename) {
    // ...
        yield $key => $line;
    // ...
}

foreach (file_lines('somefile') as $key => $line) {
    // do some work here
}
?></code>

结论

随着生成器的引入,PHP为开发人员提供了一个强大的工具。我们现在可以快速编写迭代器,同时节省大量内存。通过本教程,我希望您已经获得了足够的知识,可以在您的项目中自己开始使用它们。就我个人而言,我已经想好了很多要重写的对象。如果您有任何想法或意见,请留下您的评论。

PHP生成器的常见问题解答

(此处应包含原文中列出的常见问题解答,由于篇幅限制,此处省略。)

以上是PHP主| PHP中的发电机的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn