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

PHP 快取技術深度解析:從原理到自訂 Cache 類別實作

     編輯:PHP 相關知識

為什麼需要快取?

隨著網站資料量增長,每次請求都查詢資料庫會造成效能瓶頸。快取將熱門資料儲存在存取速度較快的介質(記憶體、檔案、Redis),下次請求直接讀取快取,大幅降低回應延遲與資料庫負載。

快取層級與介質比較

層級介質速度容量持久性典型用途
Opcode記憶體極快小進程存活期PHP 編譯後 bytecode (OPcache)
資料快取記憶體極快中TTL 過期Redis、Memcached、APCu
頁面片段記憶體/檔案快中TTL 過期Smarty block cache、Laravel view cache
靜態檔案磁碟中大手動/自動清除生成 HTML、JSON 靜態檔
HTTP 快取瀏覽器/CDN最快(無請求)大Cache-Control靜態資源、API 回應

PHP 內建輸出緩衝

<?php
ob_start(); // 開啟輸出緩衝
echo "頁面內容...";
$content = ob_get_contents(); // 取得緩衝內容
ob_end_clean(); // 清除緩衝並關閉

// 或直接輸出並關閉
ob_end_flush();

// 靜態頁面生成範例
ob_start();
include 'template.php';
$html = ob_get_clean();
file_put_contents('static/page.html', $html);
?>

自訂檔案快取類別實作(教學用)

<?php
class FileCache {
    private string $cacheDir;
    private int $defaultTtl = 180; // 秒

    public function __construct(string $cacheDir) {
        if (!is_dir($cacheDir)) {
            if (!mkdir($cacheDir, 0755, true) && !is_dir($cacheDir)) {
                throw new RuntimeException("無法建立快取目錄:$cacheDir");
            }
        }
        $this->cacheDir = rtrim($cacheDir, '/');
    }

    public function set(string $key, $data, int $ttl = 0): bool {
        $ttl = $ttl ?: $this->defaultTtl;
        $file = $this->cacheDir . '/' . $this->sanitizeKey($key);
        $payload = serialize([
            'data' => $data,
            'expire' => time() + $ttl,
        ]);
        
        // 原子寫入:寫入暫存檔再 rename,避免並發讀到半寫入資料
        $tmpFile = $file . '.tmp.' . random_bytes(8);
        if (file_put_contents($tmpFile, $payload) === false) return false;
        if (!rename($tmpFile, $file)) {
            @unlink($tmpFile);
            return false;
        }
        return true;
    }

    public function get(string $key, $default = null) {
        $file = $this->cacheDir . '/' . $this->sanitizeKey($key);
        if (!is_file($file)) return $default;
        
        $payload = @unserialize(file_get_contents($file));
        if (!$payload || !isset($payload['expire'], $payload['data'])) {
            @unlink($file); // 損壞檔案刪除
            return $default;
        }
        if (time() > $payload['expire']) {
            @unlink($file); // 過期刪除
            return $default;
        }
        return $payload['data'];
    }

    public function delete(string $key): bool {
        $file = $this->cacheDir . '/' . $this->sanitizeKey($key);
        return is_file($file) && unlink($file);
    }

    public function clear(): int {
        $count = 0;
        foreach (glob($this->cacheDir . '/*') as $file) {
            if (is_file($file) && unlink($file)) $count++;
        }
        return $count;
    }

    private function sanitizeKey(string $key): string {
        // 僅允許英數字、底線、連字號、點,防止路徑遍歷
        return preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $key);
    }
}

// 使用範例
$cache = new FileCache(__DIR__ . '/cache');

// 寫入
$cache->set('user:1001', ['name' => 'John', 'role' => 'admin'], 300);

// 讀取
$user = $cache->get('user:1001');
if ($user === null) {
    // 快取未命中:查詢資料庫
    $user = $db->query("SELECT * FROM users WHERE id = 1001")->fetch();
    $cache->set('user:1001', $user, 300);
}
?>

生產環境建議:使用成熟方案

  • APCu:單機記憶體快取,無網路開銷,適合中小型專案。
  • Redis:支援叢集、資料結構豐富、持久化、發布訂閱,企業級首選。
  • Memcached:簡單高效的分散式記憶體快取,純 LRU 淘汰。
  • 框架整合:Laravel Cache::、Symfony CacheInterface、Yii yii\caching\Cache 統一介面,切換後端零修改業務碼。

快取策略與常見模式

模式適用場景關鍵點
Cache-Aside (Lazy Loading)讀多寫少、容許短暫不一致應用層負責讀寫快取,失效由應用決定
Write-Through資料一致性要求高寫入時同步更新快取與資料庫
Write-Behind寫入極頻繁、可容忍延遲持久化非同步批次寫入資料庫,需防資料遺失
Refresh-Ahead可預測的熱點資料背景預先重建快取,避免冷啟動延遲

總結

快取是高效能 PHP 架構的核心組件。理解各層級快取特性、掌握 Cache-Aside 基本模式、選擇合適的後端(Redis/APCu),並建立完善的快取失效、監控、預熱機制,才能在流量增長時保持系統穩定回應。

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