針對現有模板引擎過於笨重、學習曲線陡峭的問題,作者開發了輕量級 pfcTemplate 類,特點:無正則解析(純字串函數)、多級區塊嵌套、支援字串/文件/資料庫多來源、標識符可定制。本文詳細講解其核心設計、API 用法與實現原理。
| 特性 | 說明 |
|---|---|
| 高效解析 | 使用 strpos、substr、str_replace 等字串函數,避免正則開銷 |
| 易用 API | 實例化 → 添加來源 → 設置變量/區塊 → 解析區塊 → 輸出 |
| 多級區塊 | 支援無限層級嵌套(...) |
| 多來源 | 文件、字串變量、資料庫 BLOB、緩存鍵值 |
| 可定制標識符 | 變量 {VAR}、區塊 可自定義格式 |
<?php
class pfcTemplate {
// 模板來源存儲 [handle => content]
private array $templates = [];
// 區塊存儲 [handle => [block_name => content]]
private array $blocks = [];
// 變量存儲 [handle => [var_name => value]]
private array $vars = [];
// 標識符配置
public string $varOpen = '{';
public string $varClose = '}';
public string $blockOpen = '';
public string $blockEndOpen = '';
// 添加文件模板
public function addFile(string $handle, string $filepath): bool {}
// 添加字串模板
public function setString(string $handle, string $content): void {}
// 設置變量
public function setVar(string $handle, string $name, $value): void {}
public function setVars(string $handle, array $vars): void {}
// 提取區塊
public function setBlock(string $handle, string $blockName, string $blockHandle): bool {}
// 解析區塊 (追加模式)
public function parse(string $blockHandle, string $sourceBlock, bool $append = false): void {}
// 解析並輸出
public function parseOut(string $handle): string {}
// 直接輸出
public function fastPrint(string $handle): void {}
}
?>
$tplStr = '
<html>
<body>
<h1>{TITLE}</h1>
<!-- BEGIN USER_ROW -->
<div>{NAME} - {EMAIL}</div>
<!-- END USER_ROW -->
</body>
</html>';
<?php
require 'pfcTemplate.php';
$tpl = new pfcTemplate();
// 可選:自定義標識符
// $tpl->varOpen = '{{';
// $tpl->varClose = '}}';
$tpl->setString('page', $tplStr);
$tpl->setVar('page', 'TITLE', '用戶列表');
// 提取區塊
$tpl->setBlock('page', 'USER_ROW', 'user_row');
$users = [
['name' => 'Alice', 'email' => 'alice@example.com'],
['name' => 'Bob', 'email' => 'bob@example.com'],
];
foreach ($users as $user) {
$tpl->setVars('user_row', $user);
// 第三參數 true = 追加模式
$tpl->parse('user_row', 'USER_ROW', true);
}
$tpl->fastPrint('page'); // 直接 echo
// 或
$html = $tpl->parseOut('page'); // 獲取字串
echo $html;
?>
模板:
<!-- BEGIN OUTER -->
外層: {OUTER_VAR}
<!-- BEGIN INNER -->
內層: {INNER_VAR}
<!-- END INNER -->
<!-- END OUTER -->
解析順序:
setBlock('page', 'OUTER', 'outer_handle') 提取外層區塊,父模板替換為 {outer_handle}。setBlock('outer_handle', 'INNER', 'inner_handle') 在外層區塊內提取內層。parse('inner_handle', 'INNER', true)。parse('outer_handle', 'OUTER', true),此時內層已展開。private function parseBlock(string $targetHandle, string $sourceBlock, bool $append) {
$blockContent = $this->blocks[$targetHandle][$sourceBlock] ?? '';
$vars = $this->vars[$targetHandle] ?? [];
// 替換變量
foreach ($vars as $name => $value) {
$placeholder = $this->varOpen . $name . $this->varClose;
$blockContent = str_replace($placeholder, $value, $blockContent);
}
// 替換子區塊佔位符 (已在子 parse 時生成)
// 子區塊解析後會在 $this->vars[$targetHandle] 生成對應佔位符鍵值
if ($append) {
$this->vars[$targetHandle][$sourceBlock] =
($this->vars[$targetHandle][$sourceBlock] ?? '') . $blockContent;
} else {
$this->vars[$targetHandle][$sourceBlock] = $blockContent;
}
}
<?php
// 從資料庫讀取模板字串
$stmt = $pdo->query("SELECT content FROM templates WHERE name = 'email_welcome'");
$templateStr = $stmt->fetchColumn();
$tpl->setString('email', $templateStr);
$tpl->setVar('email', 'USERNAME', $user->name);
$tpl->fastPrint('email');
?>
| 引擎 | 解析方式 | 10000 次渲染 | 記憶體 | 學習成本 |
|---|---|---|---|---|
| pfcTemplate | 字串函數 | ~0.15s | 低 | 極低 |
| Smarty 3 | 編譯 PHP | ~0.30s | 中 | 中 |
| Twig 3 | 編譯 PHP | ~0.25s | 中 | 中 |
| 原生 PHP include | 無 | ~0.05s | 最低 | 無 |
pfcTemplate 以零依賴、零正則、API 極簡為優勢,適合:輕量專案、不想引入 Composer、模板邏輯簡單(變量替換+區塊循環)、需從資料庫讀取模板的場景。但缺乏自動逃逸、沙箱、繼承、插件機制,複雜專案建議使用 Twig/Blade。理解其「字串提取區塊→變量替換→追加合併」的核心流程,可自行擴展或參考設計輕量模板系統。