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

Smarty 模板引擎快取機制深度解析:全域、區塊、動態區塊與清除策略

     編輯:PHP 綜合知識

前言

Smarty 的快取機制是其核心優勢之一,透過「編譯模板為 PHP」+「快取輸出結果」雙層加速,大幅降低 CPU 與資料庫負載。本文深入解析快取層級、動態區塊處理、清除策略與實戰調優。

一、快取基礎概念

層級名稱儲存內容更新觸發
L1編譯快取模板編譯後的 PHP 代碼 (`templates_c/`)模板檔修改時間變更
L2輸出快取模板執行後的 HTML 輸出 (`cache/`)快取過期 / 手動清除 / 依賴資料變更

二、啟用全域快取

$smarty->caching = true;              // 開啟 L2 快取
$smarty->cache_lifetime = 3600;       // 快取壽命:3600 秒 (1小時)
$smarty->cache_dir = '/path/to/cache/'; // 快取目錄 (需寫入權限)

// 檢查是否有效快取 (避免不必要的資料庫查詢)
if (!$smarty->isCached('index.tpl')) {
  // 只有無快取時才查詢資料庫
  $data = $db->query('SELECT * FROM products')->fetchAll();
  $smarty->assign('products', $data);
}

$smarty->display('index.tpl');

三、一個模板多組快取 (Cache ID)

適用場景:同一模板顯示不同資料(如:不同分類商品列表、不同用戶個人頁)

// 使用分類 ID 作為 cache_id
$cacheId = 'cat_' . (int)$_GET['cat_id'];

if (!$smarty->isCached('product_list.tpl', $cacheId)) {
  $products = $db->query('SELECT * FROM products WHERE cat_id = ?', [$cacheId])->fetchAll();
  $smarty->assign('products', $products);
}

$smarty->display('product_list.tpl', $cacheId);

四、清除快取策略

// 清除所有快取
$smarty->clearAllCache();

// 清除特定模板所有快取
$smarty->clearCache('index.tpl');

// 清除特定模板特定 cache_id
$smarty->clearCache('product_list.tpl', 'cat_5');

// 清除過期快取 (可排程每小時執行)
$smarty->clearCache(null, null, time() - 3600);  // 清除 1 小時前的快取

// 依關鍵字清除 (Smarty 3.1+)
$smarty->clearCache('index.tpl', '', 'product_');  // 清除 cache_id 含 product_ 的快取

五、動態區塊:局部不快取 (三種方法)

方法 1:{insert} 標籤 (最簡單、預設不快取)

<!-- 模板 -->
<div class="header">
  <{insert name="user_panel"}>
</div>
<?php
// PHP 註冊 insert 函數 (命名規則: insert_標籤名)
function insert_user_panel($params, $smarty) {
  // 這裡的程式碼每次都會執行,不受快取影響
  if (isset($_SESSION['user'])) {
    return '歡迎,' . $_SESSION['user']['name'] . ' | 登出';
  }
  return '登入 | 註冊';
}

// 使用前不需額外註冊,Smarty 會自動尋找 insert_xxx 函數
?>

方法 2:{block} 區塊 + registerBlock (靈活控制)

<?php
// 定義 block 處理函數
function smarty_block_dynamic($params, $content, $smarty) {
  return $content;  // 直接回傳內容,但此區塊不被快取
}

// 註冊 block,第 3 參數 false = 不快取
$smarty->registerBlock('dynamic', 'smarty_block_dynamic', false);
?>
<!-- 模板 -->
<div class="sidebar">
  <{dynamic}>
    目前線上人數: <{$online_count}>  <!-- 這裡每次都重新渲染 -->
  <{/dynamic}>
</div>

方法 3:自訂函數 + registerPlugin (function, false)

<?php
function smarty_function_current_time($params, $smarty) {
  return date('Y-m-d H:i:s');
}

// 註冊函數,第 3 參數 false = 不快取輸出
$smarty->registerPlugin('function', 'current_time', 'smarty_function_current_time', false);
?>
<!-- 模板 -->
<div class="footer">
  目前時間: <{current_time}>
</div>

六、快取依賴與資料更新同步

核心問題:資料庫資料異動時,如何讓對應快取失效?

策略 1:版本號/時間戳作為 Cache ID 一部分

// 取得資料表最後更新時間
$lastUpdate = $db->query("SELECT MAX(updated_at) FROM products")->fetchColumn();
$cacheId = 'products_v' . $lastUpdate;

if (!$smarty->isCached('product_list.tpl', $cacheId)) {
  $products = $db->query('SELECT * FROM products')->fetchAll();
  $smarty->assign('products', $products);
}
$smarty->display('product_list.tpl', $cacheId);

策略 2:資料異動時主動清除相關快取

// 商品更新後
function updateProduct($id, $data) {
  global $smarty;
  $db->update('products', $data, ['id' => $id]);
  
  // 清除所有相關快取
  $smarty->clearCache('product_list.tpl');           // 列表頁
  $smarty->clearCache('product_detail.tpl', 'prod_' . $id); // 詳情頁
  $smarty->clearCache('home.tpl', '', 'product_');   // 首頁推薦區塊
}

策略 3:使用快取標籤/群組 (需額外實作或使用 Smarty Cache Resource)

Smarty 內建不支援標籤式清除,可自行實作:

// 簡易版:快取檔命名規則 {template}_{cacheId}_{tags}.php
// 寫入時記錄 tags,清除時掃描 cache/ 目錄刪除含特定 tag 的檔案

七、效能調優實戰建議

場景建議配置
高流量首頁`cache_lifetime = 300` (5分鐘) + 靜態化輸出 HTML 到 nginx 直接服務
用戶個人頁使用 `cache_id = 'user_' . $uid`,登入狀態區塊用 `{insert}`
商品列表頁`cache_id = 'cat_' . $catId . '_p' . $page`,分頁各自快取
資料頻繁變動縮短 `cache_lifetime` 或改用策略 2 主動清除
大量模板定期清理 `templates_c/` 避免 inode 耗盡

八、常見誤區

  1. 以為開啟 caching 就萬事大吉:沒搭配 `isCached()` 判斷,資料庫查詢仍會執行
  2. 動態內容未標記:用戶名、購物車數量、CSRF token 等被快取,導致所有用戶看到同樣內容
  3. 清除快取不徹底:更新資料只清除列表頁,詳情頁、首頁推薦、搜尋結果頁殘留舊快取
  4. 快取目錄權限錯誤:PHP 無寫入權限導致快取失效、每次重新編譯
  5. 開發環境未關閉快取:修改模板不生效,浪費除錯時間

總結

Smarty 快取機制威力強大,但關鍵在於精準控制快取顆粒度(Cache ID)、正確標記動態區塊(insert/block/function, false)、建立資料異動同步清除機制。掌握這三點,即能在開發效率與執行效能間取得最佳平衡。

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