php页面缓存需服务端存储(如文件/redis)、客户端协商(cache-control+last-modified/etag)和框架层拦截三者对齐;常见失效原因包括缓存逻辑位置错误、键不唯一、未绕过中间逻辑、或混淆数据缓存与页面缓存。

PHP 页面缓存机制不是“开个开关”就能生效的,它必须分清是服务端缓存(如文件/Redis 缓存 HTML 输出)还是客户端缓存(如 Cache-Control、Last-Modified),两者作用位置、生效条件、调试方式完全不同。混用或只做一半,基本等于没做。
用 ob_start() + 文件缓存时,为什么缓存文件生成了但没生效?
常见错误是缓存逻辑写在页面底部、或被 exit/die 截断,导致缓存写入前脚本已终止;也可能是缓存路径权限不足或未创建目录。
- 缓存判断必须放在所有输出之前,最好在入口文件最顶部(如
index.php开头) -
$cacheFile路径需确保父目录存在且 PHP 有写权限,建议加is_writable(dirname($cacheFile))检查 - 不要在缓存判断后还执行数据库查询或耗时操作——缓存命中时应直接
exit,否则浪费资源 - 示例关键片段:
if (file_exists($cacheFile) && (time() - filemtime($cacheFile))
用 Redis 缓存页面内容,$redis->setex() 的第三个参数填错会怎样?
填成时间戳(如 time() + 3600)会导致缓存立即过期,因为 setex 第三个参数是「秒数」,不是时间戳。Redis 会静默接受错误值,但实际不缓存或缓存极短时间,现象就是“好像没缓存”。
- 务必确认传入的是正整数秒,例如
3600(1 小时)、600(10 分钟) - 键名(
$key)要能区分不同参数请求,比如含$_GET参数哈希:'page_' . md5($_SERVER['REQUEST_URI']) - 连接失败时
$redis->get()返回false,不能直接echo,需判空再走回源逻辑 - 若用
phpredis扩展,确保已启用;若用Predis,方法名可能为setEx()(大小写敏感)
怎么让浏览器也缓存 PHP 动态页?光设 header('Cache-Control: max-age=3600') 不够
单独设置 Cache-Control 只控制“能否缓存”和“缓存多久”,但浏览器是否真用缓存,还取决于 ETag 或 Last-Modified 是否匹配。PHP 动态页没有天然的“最后修改时间”,必须手动提供。
- 如果内容由数据库驱动,可用数据最新更新时间作为
Last-Modified值:$lastModified = date('D, d M Y H:i:s', $row['updated_at']) . ' GMT'; header('Last-Modified: ' . $lastModified); - 配合
Cache-Control: public, max-age=3600,浏览器会在过期前直接复用本地副本 - 若内容变化频繁但结构固定(如带时间戳的仪表盘),建议改用
Cache-Control: no-cache+ETag,由服务端做弱校验 - 注意:PHP 默认开启
session_start()会隐式发送Cache-Control: no-cache,需在session_start()前手动覆盖
ThinkPHP 等框架里直接调 Cache::set(),为什么页面还是没缓存?
框架的 Cache 类默认缓存的是「数据」,不是「完整 HTML 输出」。你缓存了用户列表数组,但模板渲染、布局组装、CSS/JS 插入等仍每次执行,性能提升有限。
- 要缓存整页,得用框架提供的「页面缓存」功能(如 ThinkPHP 的
cache行为或output_cache中间件),不是通用Cache类 - 检查配置中是否启用了
output_cache,以及缓存类型(type)是否支持页面级(file或redis可以,apc等部分驱动不支持) - 路由或控制器方法上需显式标注缓存规则,例如 ThinkPHP 的
['cache' => 3600]数组配置 - 开发环境常默认关闭缓存,确认
app_debug为false,否则缓存逻辑可能被跳过
真正有效的页面缓存,从来不是单点配置,而是服务端存储 + 客户端协商 + 框架层拦截三者对齐。最容易被忽略的是:缓存键是否真的唯一、缓存失效是否可预期、以及缓存命中的路径是否绕过了所有中间逻辑。漏掉任意一环,流量就照旧打到 PHP-FPM 上。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











