循环调用file_get_contents()变慢因每次触发open→read→close系统调用,叠加内核开销;PHP还需重复分配内存、解析路径、检查权限,机械硬盘或高并发下更明显。

为什么循环里调用 file_get_contents() 会变慢
每次调用 file_get_contents() 都会触发一次完整的文件系统调用:open → read → close。在循环中反复执行,等于反复打开/关闭同一文件(或不同小文件),内核开销叠加,尤其在机械硬盘或高并发下更明显。PHP 还要为每次调用分配内存、做路径解析、检查权限,这些都不可忽略。
优先缓存内容,而不是反复读取
如果循环处理的是固定一批文件(比如配置列表、模板片段),最直接的优化是把内容提前读进内存,循环只操作数组:
- 用
array_map('file_get_contents', $file_list)一次性预加载,后续循环直接用索引访问 - 若文件内容不变,加一层 APCu 缓存:
apcu_fetch($key) ?: apcu_store($key, file_get_contents($path), 3600) - 注意:不要对 >10MB 的文件做缓存,否则挤占共享内存;缓存键建议包含
filemtime($path)防止 stale
改用 fopen() + fread() 复用句柄
当必须边循环边读(比如逐块处理大日志)、且文件固定时,避免重复 open/close:
- 循环外用
$fp = fopen($path, 'rb')打开一次 - 循环内用
fread($fp, 8192)分块读,或fgets($fp)按行读 - 循环结束后
fclose($fp)—— 忘记这步会导致句柄泄漏,Linux 下最多 1024 个限制很快耗尽 - 务必检查
fopen()返回值:if (!$fp) { throw new RuntimeException('无法打开 ' . $path); }
路径和权限问题常被忽略
看似 IO 慢,实际卡在路径解析或权限检查上:
立即学习“PHP免费学习笔记(深入)”;
- 用绝对路径代替相对路径,避免每次调用都从
getcwd()开始解析,例如写成__DIR__ . '/data/items.json' - 确认 PHP 进程对目标目录有
rx权限(不仅是文件),否则每次都会触发 SELinux 或 AppArmor 审计延迟 - 检查
open_basedir是否限制了路径范围,错误日志里会出现file_get_contents(): open_basedir restriction in effect - 如果文件在 NFS 或远程挂载卷上,
stat()调用本身就会显著拖慢,这种场景应考虑本地缓存副本



















