PHP yield
关键字
最后修改于 2025 年 4 月 16 日
PHP 的 yield
关键字创建生成器函数,这些函数可以暂停执行并一次返回一个值。生成器提供内存高效的迭代大型数据集,而无需构建数组。它们在处理数据序列和流时非常强大。
基本定义
生成器函数是一种特殊的函数,它使用 yield
而不是 return
。调用时,它会返回一个可以迭代的 Generator 对象。每次迭代都会从上一个 yield 恢复执行。
yield
关键字既为迭代器提供了值,又暂停了函数执行。当请求下一个值时,执行会恢复。这使得能够内存高效地处理大型数据集。
生成器实现了 Iterator 接口,因此它们可以与 foreach 循环一起使用。它们在 yield 之间维护其状态,包括局部变量的值。生成器可以在迭代期间同时 yield 和接收值。
基本生成器函数
此示例演示了一个简单的生成器函数,该函数 yield 三个值。
<?php declare(strict_types=1); function numberGenerator() { yield 1; yield 2; yield 3; } foreach (numberGenerator() as $number) { echo $number . "\n"; }
numberGenerator
函数按顺序 yield 三个数字。调用时,它会返回一个可以迭代的 Generator 对象。每次 yield 都会暂停执行,直到下一个迭代。foreach 循环一次消耗一个值。
生成范围
此示例显示了如何创建内存高效的范围生成器。
<?php declare(strict_types=1); function xrange($start, $limit, $step = 1) { for ($i = $start; $i <= $limit; $i += $step) { yield $i; } } foreach (xrange(1, 1000000) as $number) { echo $number . "\n"; }
xrange
生成器在不创建数组的情况下生成从 start 到 limit 的数字。无论范围大小如何,它都使用恒定的内存。这与 range() 不同,后者会在内存中构建整个数组。生成器在大型序列方面表现出色。
Yield 键值对
此示例演示了从生成器 yield 关联键值对。
<?php declare(strict_types=1); function userGenerator() { yield 'id' => 1; yield 'name' => 'John Doe'; yield 'email' => 'john@example.com'; } foreach (userGenerator() as $key => $value) { echo "$key: $value\n"; }
生成器 yield 键值对,这些键值对可以在 foreach 循环中消耗。此语法类似于数组迭代。每次 yield 都同时提供键和值。生成器可以在不存储所有元素的情况下模拟关联数组。
接收值
此示例显示了生成器如何在迭代期间接收值。
<?php declare(strict_types=1); function echoingGenerator() { echo "Generator started\n"; $input = yield; echo "Received: $input\n"; $input = yield; echo "Received: $input\n"; } $gen = echoingGenerator(); $gen->send('First'); $gen->send('Second');
生成器在首次调用时启动。send
方法向生成器提供值。每次 send 都会恢复执行,直到下一个 yield。值成为 yield 表达式的结果。这使得能够进行双向通信。
内存效率
此示例比较了数组方法和生成器方法之间的内存使用情况。
<?php declare(strict_types=1); function generateLines($file) { $handle = fopen($file, 'r'); while (!feof($handle)) { yield fgets($handle); } fclose($handle); } // Array approach would load entire file into memory foreach (generateLines('large_file.txt') as $line) { // Process each line }
生成器一次读取一行,使用最少的内存。数组方法会一次性加载整个文件。生成器非常适合大型数据集。内存使用量与输入大小无关,保持恒定。这使得能够处理大于可用内存的文件。
无限序列
此示例演示了如何使用生成器创建无限序列。
<?php declare(strict_types=1); function fibonacci() { $a = 0; $b = 1; while (true) { yield $a; [$a, $b] = [$b, $a + $b]; } } $count = 0; foreach (fibonacci() as $number) { echo $number . "\n"; if (++$count > 10) break; }
斐波那契生成器创建了一个没有内存问题的无限序列。while(true)
循环对于数组来说很危险,但对于 yield 来说是安全的。消费者控制何时停止迭代。这种模式对于数学序列和流很有用。
生成器委托
此示例展示了如何使用 yield from 委托给另一个生成器。
<?php declare(strict_types=1); function countToThree() { yield 1; yield 2; yield 3; } function countToFive() { yield from countToThree(); yield 4; yield 5; } foreach (countToFive() as $number) { echo $number . "\n"; }
yield from
语法委托给另一个生成器。来自内部生成器的值直接 yield 给调用者。这使得生成器组合和代码重用成为可能。委托完成后,执行会返回到外部生成器。
最佳实践
- 内存:对大型数据集使用生成器以节省内存。
- 性能:生成器在单次迭代中速度很快。
- 可重用性:生成器结果无法倒带或重用。
- 清晰度:为其他开发人员记录生成器行为。
- 兼容性:与所有 PHP 迭代构造一起使用。
来源
本教程涵盖了 PHP 生成器,并通过实际示例展示了 yield 的用法,用于内存高效迭代、无限序列和数据处理。
作者
列出 所有 PHP 教程。