Smarty 是 PHP 經典的模板引擎,透過「編譯模板為 PHP 程式碼」機制,兼顧效能與設計師友善語法。雖然現代框架多內建 Blade、Twig,但大量存量專案仍在使用 Smarty 3.x。本文系統整理核心用法,作為維護與遷移參考。
require_once __DIR__ . '/libs/Smarty.class.php';
$smarty = new Smarty();
// 目錄設定(建議放在配置檔)
$smarty->setTemplateDir(__DIR__ . '/templates/');
$smarty->setCompileDir(__DIR__ . '/templates_c/');
$smarty->setCacheDir(__DIR__ . '/cache/');
$smarty->setConfigDir(__DIR__ . '/configs/');
// 自定義分隔符,避免與 JS 模板衝突
$smarty->left_delimiter = '{{';
$smarty->right_delimiter = '}}';
// 開發環境關閉快取、啟用錯誤報告
if (APP_ENV === 'dev') {
$smarty->caching = false;
$smarty->force_compile = true;
$smarty->debugging = true;
}
// 純量
$smarty->assign('siteName', 'MySite');
$smarty->assign('user', ['name' => 'Alice', 'role' => 'admin']);
// 批次指派
$smarty->assign([
'title' => '歡迎頁',
'items' => ['Apple', 'Banana', 'Cherry'],
]);
// 模板中輸出
// {{ $siteName }}
// {{ $user.name }} / {{ $user['name'] }}
// {{ $items[0] }}
{* foreach:適用關聯陣列,支援 key、name 屬性 *}
{{ foreach $items as $key => $item name=loop }}
{{ $key }}: {{ $item }}
{{ if $smarty.foreach.loop.first }}首項{{ /if }}
{{ if $smarty.foreach.loop.last }}尾項{{ /if }}
迭代次數:{{ $smarty.foreach.loop.iteration }}
{{ /foreach }}
{* section:適用索引陣列,較舊語法 *}
{{ section name=sec loop=$items }}
索引:{{ $smarty.section.sec.index }}
序號:{{ $smarty.section.sec.iteration }}
值:{{ $items[sec] }}
{{ /section }}
{* 條件判斷 *}
{{ if $user.role === 'admin' }}
後台
{{ elseif $user.logged_in }}
歡迎,{{ $user.name }}
{{ else }}
登入
{{ /if }}
| 修飾符 | 用途 | 範例 |
|---|---|---|
|escape:'html' | HTML 實體化(預設) | {{ $input|escape }} |
|escape:'url' | URL 編碼 | {{ $link|escape:'url' }} |
|date_format:'%Y-%m-%d' | 日期格式化 | {{ $timestamp|date_format:'%Y-%m-%d' }} |
|truncate:30:'...' | 截斷字串 | {{ $desc|truncate:30:'...' }} |
|replace:'old':'new' | 字串取代 | {{ $url|replace:'http:':'https:' }} |
|regex_replace:'/pattern/':'repl' | 正則取代 | {{ $text|regex_replace:'/\d+/':'*' }} |
|lower / |upper | 大小寫轉換 | {{ $name|upper }} |
|indent:4:'*' | 縮排 | {{ $code|indent:4:'*' }} |
|default:'預設值' | 預設值 | {{ $var|default:'N/A' }} |
{* 包含子模板 *}
{{ include file='header.tpl' title='頁面標題' }}
{* 模板繼承 (Smarty 3+) *}
{* layouts/main.tpl *}
{{ $title|default:'預設標題' }}
{{ block name=content }}{{ /block }}
{{ include file='footer.tpl' }}
{* child.tpl *}
{{ extends file='layouts/main.tpl' }}
{{ block name=content }}
子頁面內容
{{ /block }}
{* 日期下拉選單 *}
{{ html_select_date prefix='birth' start_year='-80' end_year='+0' field_order='YMD' }}
{* 選項循環(表格斑馬紋) *}
{{ foreach $rows as $row }}
{{ $row.name }}
{{ /foreach }}
{* 郵件連結編碼防採集 *}
{{ mailto address='admin@example.com' encode='javascript' subject='聯絡我們' }}
// plugins/modifier.truncate_zh.php
function smarty_modifier_truncate_zh($string, $length = 30, $etc = '...', $breakWords = false) {
if (mb_strlen($string, 'UTF-8') <= $length) return $string;
return mb_substr($string, 0, $length, 'UTF-8') . $etc;
}
// 註冊(或放入 plugins 目錄自動載入)
$smarty->registerPlugin('modifier', 'truncate_zh', 'smarty_modifier_truncate_zh');
{{ $longText|truncate_zh:50 }}
$smarty->caching = true; $smarty->cache_lifetime = 3600;{block name='sidebar' cache_lifetime=300} 只快取局部。{nocache} 標記動態區塊:{nocache}{$dynamicVar}{/nocache}。templates_c/ 可寫,且不在網站根目錄下(防直接存取)。新專案建議採用 Twig(Symfony、Laravel Blade 內建)或 Blade(Laravel),語法更現代、安全(預設逃逸)、支援模板繼承、擴充性更強。存量 Smarty 專案可逐步以「Strangler Fig」模式替換:新功能用新引擎,舊模板維持運行,邊緣服務層整合輸出。
掌握 Smarty 核心語法與優化技巧,能高效維護舊專案,亦能為架構遷移鋪平道路。