首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 文件緩存函數:基於序列化數據與模板的輕量級緩存實現

     編輯:PHP 綜合知識

一個簡單實用的 PHP 文件緩存函數:__cache() 完整解析

在無 Redis/Memcached 的環境下,文件緩存是提升頁面響應速度的經典方案。本文解析一個集「數據查詢、模板渲染、序列化存儲、過期驗證」於一體的緩存函數,適合中小型項目快速接入。

函數簽名與參數說明

function __cache($cachefile, $pertime, $sql, $templatefile) {
    // $cachefile: 緩存文件絕對路徑
    // $pertime: 緩存有效期(秒)
    // $sql: 查詢 SQL 語句
    // $templatefile: 模板文件路徑(不含 .php 後綴)
}

完整實現代碼

function __cache($cachefile, $pertime, $sql, $templatefile) {
    global $db;  // 依賴全局 $db 對象,需具備 query()、fetch() 方法

    // 判斷緩存是否過期:當前時間 - 文件修改時間 >= 有效期
    if (time() - @filemtime($cachefile) >= $pertime) {
        // --- 緩存過期或不存在:重新構建 ---
        $query = $db->query($sql);
        $cachelist = [];
        while ($r = $db->fetch($query)) {
            $cachelist[] = $r;
        }

        // 包含模板文件,模板中直接使用 $cachelist 變量輸出 HTML
        // 模板輸出會被緩存捕獲(需配合 ob_start 或模板內直接輸出)
        include $templatefile . '.php';

        // 將渲染後的數據序列化存儲
        // 注意:此處序列化的是 $cachelist 數組,而非模板輸出的 HTML
        $cacheserialize = serialize($cachelist);
        file_put_contents($cachefile, $cacheserialize);
    } else {
        // --- 緩存有效:直接讀取反序列化 ---
        $cachelist = unserialize(file_get_contents($cachefile));
        include $templatefile . '.php';
    }
}

工作流程圖解

請求到達
   │
   ▼
檢查緩存文件修改時間
   │
   ├─ 過期/不存在 ──▶ 執行 SQL 查詢 ──▶ 獲取數據數組
   │                        │
   │                        ▼
   │                  include 模板文件(渲染 HTML)
   │                        │
   │                        ▼
   │                  serialize 數據數組
   │                        │
   │                        ▼
   │                  file_put_contents 寫入緩存文件
   │
   └─ 未過期 ─────────▶ file_get_contents 讀取
                            │
                            ▼
                      unserialize 還原數據
                            │
                            ▼
                      include 模板文件(渲染 HTML)

關鍵問題與改進建議

1. 模板渲染輸出未捕獲(關鍵缺陷)

代碼中 include $templatefile 直接輸出到瀏覽器,但緩存存儲的是 $cachelist 而非渲染後的 HTML。這意味著:

  • 首次請求:正常輸出 HTML,但緩存存的是原始數據
  • 後續請求:讀取數據,再次 include 模板渲染
  • 未實現真正的「靜態化緩存」,每次仍需執行模板渲染邏輯

修正方案:使用輸出緩衝捕獲 HTML:

if (time() - @filemtime($cachefile) >= $pertime) {
    // ... 查詢數據 ...
    ob_start();
    include $templatefile . '.php';
    $html = ob_get_clean();
    file_put_contents($cachefile, $html);  // 直接存 HTML
} else {
    echo file_get_contents($cachefile);  // 直接輸出 HTML
}

2. 依賴全局 $db 耦合度高

建議傳入 PDO/mysqli 實例或使用依賴注入容器。

3. 緩存文件並發競爭

高並發下多進程可能同時重建緩存(「緩存擊穿」)。建議加文件鎖:

$fp = fopen($cachefile . '.lock', 'w');
flock($fp, LOCK_EX);
// ... 重建邏輯 ...
flock($fp, LOCK_UN);
fclose($fp);

4. 無緩存清理機制

需定時任務清理過期文件,避免磁盤佔滿。

適用場景總結

適用不適用
中小流量項目,無緩存中間件高並發、分佈式部署(文件鎖不可跨機器)
數據更新頻率低、讀多寫少實時性要求極高的數據
快速原型、內部工具大數據量(文件 IO 成為瓶頸)

這個函數展示了文件緩存的核心邏輯,理解其原理與缺陷,有助於在選型時做出正確決策:能用 Redis 就別用文件,必須用文件時請注意並發與輸出捕獲。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved