yield能省内存是因为不一次性构建完整数组,而是边计算边产出单个值,内存占用稳定在几百KB;典型场景包括大文件逐行处理、数据库游标遍历、递归树展开和实时日志解析。

yield 生成器为什么能省内存
因为 yield 不一次性把所有数据装进数组,而是每次只产出一个值,用完就扔。普通 foreach 遍历大数组时,整个数组得常驻内存;而用生成器,哪怕处理百万行数据库结果或超大文件,内存占用通常稳定在几百 KB 级别。
关键不是“语法酷”,是 PHP 在底层根本没构建完整数组——它靠迭代器协议边算边交,上层代码感知不到中间态。
什么时候必须用 yield 而不是 return 数组
典型场景:读取大文件逐行处理、数据库游标式遍历、递归树结构展开、实时日志流解析。这些场景下,你根本不知道总量有多大,或者压根不需要随机访问。
- 数据库查询返回 50 万条记录?
return $pdo->fetchAll()可能直接 OOM;改用yield每次只 fetch 一条,内存几乎不涨 - 解析 2GB 的 CSV?
fgets()+yield比file_get_contents()+explode()安全十倍 - 写递归目录扫描?
yield from scanDir($path)避免深递归栈溢出,也避免把全部路径存进内存
常见踩坑:yield 写错位置或混用 return
最常犯的错是函数里既写了 yield 又写了 return $value(非 null)——PHP 7.1+ 会报 ParseError: A generator must not return a value。生成器函数只能 yield,结尾自然退出,不能 return 123。
立即学习“PHP免费学习笔记(深入)”;
另一个隐形坑:生成器对象本身不执行逻辑,只有第一次 foreach 或调用 current() 时才触发。如果忘了遍历,函数体压根不会跑。
示例对比:
function bad() {
yield 'a';
return 'b'; // ❌ 错误!PHP 直接拒绝编译
}
function good() {
yield 'a';
yield 'b'; // ✅ 正确
// 什么也不 return,或只 return;(等价于 return null)
}
yield from 怎么安全委托子生成器
yield from 不是语法糖,它会把子生成器的每个 yield 值原样透传,并自动处理子生成器的返回值(作为父生成器本次 yield from 表达式的值)。但要注意:子生成器必须是可迭代的,比如另一个生成器函数、ArrayIterator,不能是普通数组。
错误写法:yield from [1,2,3] —— 这会直接抛 Fatal error: Uncaught Exception: Cannot use "yield from" with arrays(PHP 7.4+)。
正确写法:
function nums() { yield 1; yield 2; yield 3; }
function wrapper() {
yield from nums(); // ✅
yield from new ArrayIterator([4,5,6]); // ✅
}
如果你真想展开数组,得自己写循环:foreach ($arr as $v) yield $v;
foreach 结束,生成器就耗尽了,再遍历得重新调用函数。这点容易被忽略,尤其在测试或调试时反复重放数据流的场景。



















