PHP处理超长文本应避免全量加载:按行用fopen()+fgets()流式读取并及时释放;按字节/字符分片用fread()+mb_substr();复杂正则切分可用preg_split()带PREG_SPLIT_OFFSET_CAPTURE返回偏移再按需提取。

PHP 处理超长文本(比如几 MB 的日志、XML 或 JSON)时直接 explode() 或 str_split() 极易触发 Fatal error: Allowed memory size exhausted——根本原因是 PHP 默认把整个字符串载入内存再操作,而字符串在内存中占两倍空间(UTF-8 字节 vs 内部 UCS-2 表示),实际爆内存比预期早得多。
用 fopen() + fgets() 按行流式读取
适用于按换行符分块(如日志、CSV 行)、文本本身有自然行边界。关键是不加载全文,只维持单行缓冲。
-
fgets($fp, $length)的$length参数必须显式指定(如 8192),否则在大文件下仍可能读整行导致溢出 - 逐行处理后立即释放变量:
$line = null;,避免引用残留阻碍 GC - 注意 Windows 行尾
\r\n和 Unix\n兼容性,trim($line)前先str_replace("\r", "", $line)
用 file_get_contents() 分段读取 + mb_substr()
当必须按字节数或字符数切分(如短信拆分、API 分片上传),且文本无可靠换行时用此法。核心是绕过字符串全载入。
- 用
fopen()配合fseek()定位,再用fread($fp, $chunk_size)每次只读固定字节数(如 64KB) - 对每段用
mb_substr($chunk, 0, $max_chars, 'UTF-8')确保中文不被截断;mb_internal_encoding('UTF-8')必须提前设好 - 若需保留语义完整性(如不切断句子),在
mb_strrpos($chunk, '.', 0, 'UTF-8')找最近句号回退切分点
用 preg_split() 的 PREG_SPLIT_OFFSET_CAPTURE 配合 substr()
适合按复杂模式(如正则分隔符)切分,但又不敢全量加载时的折中方案。它不返回子串,只返回偏移位置,后续按需提取。
立即学习“PHP免费学习笔记(深入)”;
- 调用
preg_split('/\s+/', $text, -1, PREG_SPLIT_OFFSET_CAPTURE)得到的是二维数组,每个元素形如[' ', 123],其中 123 是空格在原文中的字节偏移 - 再用
substr($text, $start, $end - $start)提取片段——但注意:此时$text仍得加载,所以仅适用于已知总长可控(如预估 - 更安全的做法是:先用
file()把文件按行载入数组(内存占用远低于单字符串),再对每行单独preg_split()
真正关键的不是选哪个函数,而是拒绝「先把全文 file_get_contents() 进来再切」这个直觉动作。流式读取、分段加载、延迟提取——这三步漏掉任何一环,内存墙就还在那儿。另外,memory_limit 临时调高只是掩耳盗铃,底层没改,OOM 只是推迟发生。











