PHP生成器的send()方法实现双向通信,首次须send(null)启动,后续可传值控制流程,支持数据库流式处理中的动态干预与状态反馈。

PHP 生成器的 send() 方法让 yield 不再只是“吐数据”,而是能“收数据”——形成真正的双向通信。这在流式处理海量数据库数据集时尤为关键:你不仅能逐条产出记录,还能在处理中途接收外部指令(如跳过、终止、动态修改参数),而无需加载全部数据到内存。
send() 的核心行为与首次调用规则
send() 向暂停在 yield 处的生成器传入一个值,该值直接成为当前 yield 表达式的返回结果。它不是简单地“唤醒”生成器,而是注入上下文信息。
- 首次调用必须是
$gen->send(null)或先用next()启动(等价于send(null)),否则会报错“未初始化的生成器” - 后续每次
send($value)都会把$value赋给$received = yield中的$received - 生成器内部可基于接收到的值做条件分支,比如
if ($received === 'stop') break;
数据库流式读取 + 动态控制的实战结构
面对千万级表,用 PDO 配合生成器逐行 fetch,并通过 send() 实现运行时干预:
- 生成器函数内使用
while ($row = $stmt->fetch())循环,每轮yield $row返回一行 - 在
yield前加一层接收逻辑:$cmd = yield $row;,允许外部发送命令 - 主循环中,用
foreach迭代生成器,遇到特定条件(如处理满1000条)时调用$gen->send('pause')或'skip' - 注意:
foreach内部隐式调用next(),若需send(),建议改用手动while ($gen->valid())+current()/send()控制
避免 foreach 中 send 的陷阱
foreach 自动推进迭代器,直接在里面调用
send()</code) 会导致跳过下一项或逻辑错乱。推荐显式控制流程:</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/7fc7563c4182" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">PHP免费学习笔记(深入)</a>”;</p> <ul> <li>用 <code>while ($gen->valid())替代
foreach
$row = $gen->current() 获取当前行$gen->send($instruction),比如 $gen->send(['limit' => 5000])
$gen->next() 推进到下一行结合日志与状态反馈的协程式处理
在 ETL 场景中,send() 可用于回传处理进度或错误上下文:
- 生成器内定义
$stats = ['processed' => 0, 'errors' => []];并在每次 yield 前更新 - 外部可通过
$gen->send(['report' => true])触发生成器返回当前统计,而非数据行 - yield 表达式可动态切换返回内容:
yield $cmd === 'report' ? $stats : $row; - 这样一条生成器就能同时服务数据流和监控流,无需额外通道



















