PHPOPcache缓存怎样刷新生效_OPcache刷新生效法【即时】

6次阅读

OPcache 修改php文件未生效是因为其默认缓存字节码且不实时校验源文件变更;开发环境应设opcache.validate_timestamps=1并调低opcache.revalidate_freq,生产环境推荐reload PHP-FPM而非opcache_reset()。

PHPOPcache缓存怎样刷新生效_OPcache刷新生效法【即时】

OPcache 缓存为什么改了 PHP 文件却没生效

因为 OPcache 默认把编译后的字节码常驻内存,不检查源文件是否变更。哪怕你 touch 了文件、重启了 Web 服务(如 apache),只要 OPcache 没被清空或重载,旧字节码就还在跑。

常见现象包括:修改了 index.php 但页面输出仍是旧逻辑;var_dump(__FILE__) 显示路径正确,但内容未更新;用 opcache_get_status() 查看发现 opcache.hit_rate 很高,但 opcache.files_count 和实际文件数对不上。

  • 开发环境建议关闭 opcache.validate_timestamps(设为 1),否则它只在每次请求时按固定间隔(默认 2 秒)检查一次时间戳,不是实时的
  • opcache.revalidate_freq 值越大,延迟越明显;设为 0 才真正“每次请求都校验”,但会牺牲性能
  • 某些 docker 或容器化部署中,宿主机改文件、容器内 PHP 进程可能因挂载方式看不到 mtime 变更,导致 validate 失效

手动刷新 OPcache 的三种可靠方式

不是所有方式都“即时”——关键看是否触发了字节码重编译,以及是否影响全部 worker 进程。

  • 调用 opcache_reset():必须在脚本中执行,且该脚本本身不能被 OPcache 缓存(否则函数根本不会运行)。推荐放在独立的 opcache-reset.php 中,并确保该文件不在 opcache.blacklist_filename 里,访问一次即重置全站缓存
  • 调用 opcache_invalidate($script, $force):只清指定文件,$force = true 才跳过时间戳校验强制重载。注意路径必须是绝对路径(可用 realpath(__FILE__) 获取)
  • 重启 PHP-FPM 进程:sudo systemctl reload php*-fpmkill -USR2 $(cat /var/run/php/php*-fpm.pid)。这是最彻底的方式,但会造成短暂请求失败(取决于进程管理策略)

别用 opcache_compile_file() 单独预热——它不触发自动依赖解析,require 的其他文件仍可能走旧缓存。

立即学习PHP免费学习笔记(深入)”;

如何确认 OPcache 刷新已生效

不能只看页面输出,得查底层状态。

  • 执行 var_dump(opcache_get_status()['scripts']),找目标文件的 timestamp 字段,对比 filemtime() 是否一致
  • 检查 opcache_get_status()['opcache_enabled'] 是否为 true,避免误操作关掉了 OPcache
  • 留意 opcache_get_status()['memory_usage']['used_memory'] 是否在 opcache_reset() 后显著下降,再缓慢回升,说明重载发生了
  • 如果用了 opcache.file_cache(启用磁盘缓存),还需清空对应目录(如 /tmp/opcache/),否则下次启动仍可能加载旧文件

生产环境慎用的“即时刷新”陷阱

所谓“即时”,在多 worker、多实例、FPM 动态子进程场景下根本不存在单点控制。

  • opcache_reset() 只作用于当前请求所在的 PHP 进程,其他 worker 进程缓存未清——你以为刷完了,其实只有 1/8 的请求看到新代码
  • 负载均衡后端有多个 PHP-FPM 实例?每个都要单独调用 opcache_reset(),或统一发信号 reload,否则必然出现新旧混跑
  • 某些云平台(如 AWS Elastic Beanstalk阿里云函数计算)禁止执行系统命令或写临时文件,opcache.file_cacheopcache_reset() 都不可用,只能靠部署时清空缓存目录 + 重启

最稳的做法其实是:部署流程中加入 systemctl reload php*-fpm,并配合健康检查确保所有 worker 已切换。临时调试才用 opcache-reset.php,且务必加 IP 白名单和随机 Token 验证。

text=ZqhQzanResources