ThinkPHP 8.0 生成器(Generator)大数据导出【省内存】
PhpStorm 是 JetBrains 推出的专业 PHP 集成开发环境,可在 Mac 上完成代码编写、智能检查、重构、调试、测试和数据库管理。它支持主流 PHP 框架、Composer、Git、Docker 与远程解释器。
ThinkPHP8.0导出百万级数据改用生成器流式处理替代全量查询,避免内存溢出。通过Db::cursor()或PDO+yield按需获取,配合关闭APP_DEBUG、禁用日志、清空Schema缓存,显著降低内存占用。
ThinkPHP 8.0 导出百万级用户数据时,内存瞬间飙到 512MB 并报错“Allowed memory size exhausted”——这问题其实不怪服务器,问题出在你还用着 Db::select() 把整张表拖进内存再 foreach。好比把长江水抽进玻璃杯,不炸才怪。正确的做法是改用生成器(Generator)流式处理,让数据按需吐出,而不是一次性加载。

用生成器替代全量查询
第一步,改写数据获取逻辑,让数据库结果集按需返回,而不是一股脑全塞进内存。在控制器或服务类中,定义一个生成器方法:
public function userGenerator(): Generator
{
$sql = "SELECT id, name, email, created_time FROM user ORDER BY id";
$pdo = $this->app->db->getPdo();
$stmt = $pdo->prepare($sql);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield $row;
}
}
注意:这里必须用原生 PDO 的 unbuffered query(未缓冲查询),否则 fetch() 仍然会预加载全部结果。ThinkPHP 默认的 Db::query() 是缓冲模式,不能直接 yield。
第二步,调用该生成器导出 CSV,每处理一行就释放变量引用:
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="users_' . date('YmdHis') . '.csv"');
$fp = fopen('php://output', 'wb');
fputcsv($fp, ['ID', '姓名', '邮箱', '注册时间']);
foreach ($this->userGenerator() as $user) {
// 关键:避免在循环内拼接大字符串或存入数组
fputcsv($fp, [$user['id'], $user['name'], $user['email'], $user['created_time']]);
// 手动触发 GC 清理潜在残留(尤其含闭包或对象时)
if (function_exists('gc_collect_cycles')) gc_collect_cycles();
}
fclose($fp);
ThinkPHP 原生支持的 Generator 封装方案
方法一:用 Db::cursor()(TP8.0+ 内置,推荐)
这是 ThinkPHP 8.0 官方提供的流式游标接口,底层已启用 PDO::MYSQL_ATTR_USE_BUFFERED_QUERY = false,无需手写 PDO。
$cursor = Db::table('user')
->field('id,name,email,created_time')
->order('id')
->cursor();
foreach ($cursor as $user) {
fputcsv($fp, [$user['id'], $user['name'], $user['email'], $user['created_time']]);
}
需要提醒的是:Db::cursor() 不支持 where 条件链式调用后直接加 ->limit()——它只接受原始 SQL 或简单条件,复杂查询请改用原生 PDO + yield 方案。
方法二:封装成可复用的 Generator 工具类
新建 app/common/Generator.php:
namespace app\common;
use think\facade\Db;
class Generator
{
public static function fromQuery(string $sql, array $params = []): Generator
{
$pdo = Db::getPdo();
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield $row;
}
}
}
控制器中调用:foreach (Generator::fromQuery("SELECT * FROM user WHERE status = ?", [1]) as $u) { ... }
导出前必须关闭的三项配置
① 关闭 APP_DEBUG:.env 中设 APP_DEBUG=false,否则调试组件和 trace 日志会额外吃掉 80MB+ 内存。
② 禁用日志写文件:config/log.php 中将驱动改为 'type' => 'socket' 或 'type' => 'redis',避免高频 fputcsv 期间被 Log::info() 阻塞。
③ 清空 Schema 缓存并重生成:执行 php think schema:clear && php think schema:build,旧缓存可能残留冗余字段映射,导致 ORM 自动附加无关关联数据。
WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,
Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。
REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。
Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许
Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator
Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。













