核心要点
yield
关键字代替return
来保存其状态,并在再次调用时从中断处继续。send()
方法来返回值和接收外部值。它还可以用于另一个生成器中,这被称为生成器委托。如果您关注过我之前关于迭代器的文章,您就会知道迭代是一个重要的编程概念,但是实现创建可迭代对象的必要接口充其量是一件麻烦事,因为需要大量的样板代码。随着PHP 5.5的发布,我们终于有了生成器!在本文中,我们将了解生成器,它提供了一种简单的方法来实现简单的迭代器,而无需Iterator接口的开销或复杂性。
生成器的工作原理
根据维基百科的定义,生成器“非常类似于返回数组的函数,因为生成器具有参数,可以被调用,并生成一系列值”。生成器基本上是一个普通的函数,但它不是返回值,而是根据需要产生任意多个值。它看起来像一个函数,但行为像一个迭代器。生成器使用yield
关键字代替return
。它的作用类似于return
,因为它将值返回给函数的调用者,但是yield
不会将函数从堆栈中移除,而是保存其状态。这允许函数从中断处继续执行。事实上,您不能从生成器中返回值,尽管您可以使用不带值的return
来终止其执行。PHP手册指出:“当调用生成器函数时,它会返回一个可以迭代的对象。”这是一个内部Generator类的对象,它以与仅向前迭代器对象相同的方式实现Iterator接口。当您迭代该对象时,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>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示例:
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
让我们用PHP重写Python生成器示例。(请注意,这两个代码片段都没有执行任何错误检查。)
<?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); ?>
生成器函数打开一个文件,然后根据需要产生文件的每一行。每次调用生成器时,它都会从中断处继续执行。它不会从头开始,因为当执行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
表达式的结果发送到生成器,并恢复执行。
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
输出将是:
<?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 } ?>
使用生成器节省内存
当您计算大型集合并且不想同时为所有结果分配内存,或者当您不知道是否需要所有结果时,生成器非常有用。由于结果的处理方式,通过仅为当前结果分配内存,可以将内存占用量减少到非常低的水平。想象一下file()
函数,它将文件中的所有行作为数组返回。对file()
函数和我们的演示file_lines()
函数运行一个简单的基准测试,每个函数都使用使用Lipsum生成的相同的随机100段文本文件,结果显示file
函数使用的内存最多是生成器的110倍。
<?php function file_lines($filename) { // ... yield $key => $line; // ... } foreach (file_lines('somefile') as $key => $line) { // do some work here } ?>
结论
随着生成器的引入,PHP为开发人员提供了一个强大的工具。我们现在可以快速编写迭代器,同时节省大量内存。通过本教程,我希望您已经获得了足够的知识,可以在您的项目中自己开始使用它们。就我个人而言,我已经想好了很多要重写的对象。如果您有任何想法或意见,请留下您的评论。
PHP生成器的常见问题解答
(此处应包含原文中列出的常见问题解答,由于篇幅限制,此处省略。)
以上是PHP主| PHP中的发电机的详细内容。更多信息请关注PHP中文网其他相关文章!