PHP主| PHP中的发电机
核心要点
- PHP生成器提供了一种简便的方法来实现迭代器,无需复杂的Iterator接口,而是使用
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中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

在PHPStorm中如何进行CLI模式的调试?在使用PHPStorm进行开发时,有时我们需要在命令行界面(CLI)模式下调试PHP�...

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

PHP8.1中的枚举功能通过定义命名常量增强了代码的清晰度和类型安全性。1)枚举可以是整数、字符串或对象,提高了代码可读性和类型安全性。2)枚举基于类,支持面向对象特性,如遍历和反射。3)枚举可用于比较和赋值,确保类型安全。4)枚举支持添加方法,实现复杂逻辑。5)严格类型检查和错误处理可避免常见错误。6)枚举减少魔法值,提升可维护性,但需注意性能优化。
