目錄約定
- 模板源文件:
data/tpl/{dir}/{tpl}.html
- 編譯緩存:
cache/tpl/{dir}/{tpl}.php
入口函數 template()
function template($tpl = 'index', $dir = 'hello') {
if (!file_exists($pd = TPL_PATH.$dir.'/')) @mkdir($pd,0777) or die("$pd目錄創建失敗");
if (!file_exists($td = TPL.$dir.'/')) @mkdir($td,0777) or die("$td目錄創建失敗");
$t2p = $pd.$tpl.'.php';
$t2h = $td.$tpl.'.html';
// 源文件更新則重新編譯
if (!file_exists($t2p) || @filemtime($t2p) < @filemtime($t2h)) {
template_go($t2p, $t2h);
}
return $t2p; // include template('header','hello');
}
編譯函數 template_go()
function template_go($t2p, $t2h) {
$str = @file_get_contents($t2h);
if ($str === false) exit("模板文件缺失,請檢查!");
$str = template_do($str);
@chmod($t2p, 0777);
return file_put_contents($t2p, $str);
}
正則替換規則 template_do()
function template_do($str) {
$str = preg_replace('/([\n\r+])\t+/s', '\\1', $str); // 去除 TAB
$str = preg_replace('/\{\$(.*)\}/Us', '<?php echo $\\1; ?>', $str); // {$var} → 輸出
$str = preg_replace('/\{php (.+)\}/', '<?php \\1 ?>', $str); // {php code} → 執行
$str = preg_replace('/\{template(.*)\}/Us', '<?php include template\\1; ?>', $str); // 子模板
$str = preg_replace('/\{include (.*)\}/Us', '<?php include "\\1"; ?>', $str); // 包含文件
$str = "<?php defined('IN_PH') or die('Access Denied');?>".$str; // 安全入口
return $str;
}
模板文件示例
<html>
<head><title>{$title}</title></head>
<body>
{php $user = getCurrentUser();}
歡迎,{$user.name}!
{template('header','common')}
{include 'sidebar.php'}
</body>
</html>
特點與不足
- 輕量、無依賴、編譯緩存性能佳。
- 正則較簡陋:不支援條件/循環標籤、變量修飾符、沙箱隔離。
- 生產建議使用成熟引擎(Smarty、Blade、Twig)。