PHP 怎么PHP 缓存控制

wen PHP项目 2

本文目录导读:

PHP 怎么PHP 缓存控制

  1. 浏览器端缓存控制(HTTP 头)
  2. 服务端输出缓存(ob_ 系列函数)
  3. Opcode 缓存(Zend Opcache)
  4. 用户态数据缓存(内存/文件)
  5. 常见问题与最佳实践

在 PHP 中,缓存控制主要涉及 浏览器端缓存(通过 HTTP 头)和 服务端缓存(如 Opcode、数据缓存)两个方面,下面从这三个维度详细说明。


浏览器端缓存控制(HTTP 头)

通过设置 header() 函数控制浏览器或代理如何缓存页面。

禁止缓存(动态页面常用)

header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP/1.1
header("Pragma: no-cache"); // HTTP/1.0
header("Expires: 0"); // 设置过期时间为过去

允许缓存,但需验证

// 缓存30秒,之后必须向服务器验证是否修改
header("Cache-Control: private, max-age=30, must-revalidate");

设置强缓存(静态资源常用)

// 缓存1年(31536000秒)
$expires = 60 * 60 * 24 * 365;
header("Cache-Control: public, max-age=" . $expires);
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $expires) . " GMT");

ETag + Last-Modified 配合 304 状态码

$lastModified = filemtime(__FILE__);
$etag = md5_file(__FILE__);
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastModified) . " GMT");
header("ETag: \"$etag\"");
// 检查客户端是否发送了 If-Modified-Since 或 If-None-Match
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
    $ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : '';
    $ifNoneMatch = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH'], '"') : '';
    if (($ifModifiedSince && strtotime($ifModifiedSince) >= $lastModified) ||
        ($ifNoneMatch && $ifNoneMatch === $etag)) {
        header("HTTP/1.1 304 Not Modified");
        exit;
    }
}
// 如果未命中缓存,输出实际内容
echo file_get_contents(__FILE__);

服务端输出缓存(ob_ 系列函数)

用于捕获 PHP 输出并延迟发送,或实现页面片段缓存。

基本用法:输出缓冲

// 开启输出缓冲
ob_start();
echo "Hello ";
echo "World";
// 获取缓冲区内容并清空
$content = ob_get_clean();
echo strtoupper($content); // 输出: HELLO WORLD

回调函数处理输出

function compress_output($buffer) {
    // 返回压缩后的内容(示例:移除多余空白)
    return preg_replace('/\s+/', ' ', $buffer);
}
ob_start("compress_output");
echo "This    is    a    test   string";
ob_end_flush();

实现页面缓存(简单示例)

$cacheFile = '/tmp/cache_' . md5($_SERVER['REQUEST_URI']) . '.html';
$cacheTime = 60; // 缓存60秒
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) {
    readfile($cacheFile);
    exit;
}
ob_start();
// ... 正常页面输出 ...
echo "<h1>动态内容</h1>";
$content = ob_get_clean();
file_put_contents($cacheFile, $content);
echo $content;

Opcode 缓存(Zend Opcache)

PHP 5.5+ 内置 Opcache,无需额外安装,在 php.ini 中配置即可。

常用配置(php.ini)

[opcache]
opcache.enable=1                    ; 启用
opcache.memory_consumption=128      ; 共享内存大小(MB)
opcache.max_accelerated_files=4000  ; 最大缓存文件数
opcache.revalidate_freq=60          ; 检查文件修改时间间隔(秒)
opcache.validate_timestamps=1       ; 启用验证时间戳

通过函数控制(如清除缓存)

// 清除整个 Opcache
opcache_reset();
// 清除指定脚本的缓存
opcache_invalidate('/path/to/file.php', true);

用户态数据缓存(内存/文件)

使用文件缓存

class FileCache {
    private $cacheDir;
    private $ttl = 3600;
    public function __construct($dir = '/tmp/cache') {
        $this->cacheDir = $dir;
        if (!is_dir($dir)) mkdir($dir, 0755, true);
    }
    public function get($key) {
        $file = $this->cacheDir . '/' . md5($key);
        if (file_exists($file) && (time() - filemtime($file) < $this->ttl)) {
            return unserialize(file_get_contents($file));
        }
        return null;
    }
    public function set($key, $value) {
        $file = $this->cacheDir . '/' . md5($key);
        file_put_contents($file, serialize($value));
    }
    public function clear() {
        array_map('unlink', glob($this->cacheDir . '/*'));
    }
}
// 使用
$cache = new FileCache();
if (!$data = $cache->get('expensive_data')) {
    $data = fetchDataFromDatabase(); // 耗时操作
    $cache->set('expensive_data', $data);
}

使用 Memcached 或 Redis

// Memcached
$memcached = new Memcached();
$memcached->addServer('localhost', 11211);
$data = $memcached->get('key');
if (!$data) {
    $data = getExpensiveData();
    $memcached->set('key', $data, 3600);
}
// Redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$data = $redis->get('key');
if (!$data) {
    $data = getExpensiveData();
    $redis->setex('key', 3600, $data);
}

常见问题与最佳实践

场景 推荐方案
动态页面(如个人账户) 设置 Cache-Control: no-cache, must-revalidate + 表单令牌
静态资源(JS/CSS/图片) 设置强缓存(max-age=一年)+ 版本号/指纹
API 响应 使用 ETag + 304 或设置短时间缓存(如 60 秒)
数据库查询结果 使用 Redis/Memcached 缓存查询结果
整页输出 使用 ob_start() + 文件缓存,或 Varnish/CDN
PHP 代码本身 启用 Opcache(生产环境必须)

PHP 缓存控制的核心思路:

  1. 浏览器端:通过 HTTP 头告诉客户端是否缓存、缓存多久
  2. 服务端输出:用 ob 系列函数捕获和复用生成的内容
  3. 代码执行:使用 Opcache 编译缓存
  4. 业务数据:用文件、Memcached 或 Redis 缓存计算结果

根据实际业务场景选择合适的缓存策略,通常需要组合多种方式才能达到最佳性能。

抱歉,评论功能暂时关闭!