ThinkPHP 2.1 的標籤庫擴充機制強大但文件較少。本文詳細記錄從建立自定義標籤類、配置導入、到實現自動載入的完整過程,避開常見坑點。
路徑慣例:@.Mylibs.Tag.TagLibTest (即 Lib/Mylibs/Tag/TagLibTest.class.php)
<?php
import('TagLib'); // 載入基類
class TagLibTest extends TagLib
{
// 定義標籤屬性
protected $tags = [
// attr: 屬性清單, close: 是否閉合(0/1), level: 巢狀層級
'article' => [
'attr' => 'name,field,limit,order,where,sql,key,mod',
'close' => 1,
'level' => 3,
],
];
/** 實作 article 標籤:查詢資料庫並迭代輸出 */
public function _article($attr, $content)
{
$tag = $this->parseXmlAttr($attr, 'article');
$resultVar = $tag['result'] ?? 'article';
$keyVar = $tag['key'] ?? 'i';
$modVal = $tag['mod'] ?? '2';
// 建構查詢 SQL
if (!empty($tag['name'])) {
$sql = "M('{$tag['name']}')";
$sql .= $tag['field'] ? "->field('{$tag['field']}')" : '';
$sql .= $tag['order'] ? "->order('{$tag['order']}')" : '';
$sql .= $tag['where'] ? "->where('{$tag['where']}')" : '';
$sql .= '->select()';
} elseif (!empty($tag['sql'])) {
$sql = "M()->query('{$tag['sql']}')";
} else {
return ''; // 無模型名也無 SQL,直接返回空
}
// 產生 PHP 模板代碼
$parseStr = "<?php \$_result={$sql}; if (\$_result): \${$keyVar}=0;";
$parseStr .= "foreach (\$_result as \$key=>\${$resultVar}):";
$parseStr .= "++\${$keyVar}; \$mod = (\${$keyVar} % {$modVal}); ?>";
$parseStr .= $content; // 標籤內容
$parseStr .= "<?php endforeach; endif; ?>";
return $parseStr;
}
}
專案 Conf/taglibs.php:
<?php
return [
'test' => '@.Mylibs.Tag.TagLibTest',
];
模板中使用:
<tagLib name="test" />
<test:article name="Article" limit="10">
<h3>{$article.title}</h3>
<p>{$article.content}</p>
</test:article>
// Conf/config.php 'TAGLIB_PRE_LOAD' => 'test',
問題:ThinkPHP 2.1 核心會嘗試實例化 TagLibTest 卻找不到類,拋出「實例化一個不存在的類」錯誤。
// ThinkPHP/Common/alias.php 'TagLibTest' => THINK_PATH . '/Lib/Think/Template/TagLib/TagLibTest.class.php',
// Lib/Action/BaseAction.class.php
class BaseAction extends Action
{
protected function _initialize()
{
import('@.Mylibs.Tag.TagLibTest');
}
}
所有控制器繼承 BaseAction 即可自動載入標籤庫,無需修改核心。
// Conf/config.php 'APP_AUTOLOAD_PATH' => 'Think.Util.,@.Mylibs.Tag.', 'TAGLIB_PRE_LOAD' => 'test',
配合自動載入路徑,清除快取後即可正常使用,無需修改任何核心檔案。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ThinkPHP 自定義標籤示範</title>
</head>
<body>
<div class="main">
<h2>自定義 article 標籤:直接查詢資料庫列表</h2>
<table border="1" cellpadding="5">
<thead>
<tr><th>ID</th><th>標題</th><th>內容</th></tr>
</thead>
<test:article name="Article" limit="10" order="id DESC">
<tr>
<td>{$article.id}</td>
<td>{$article.title}</td>
<td>{$article.content}</td>
</tr>
</test:article>
</table>
</div>
</body>
</html>
| 現象 | 原因 | 解決 |
|---|---|---|
| 標籤不生效、原樣輸出 | 未導入標籤庫或別名錯誤 | 檢查 taglibs.php、tagLib name、APP_AUTOLOAD_PATH |
| 報錯「實例化不存在的類」 | TAGLIB_PRE_LOAD 載入時機早於自動載入 | 改用方案 C 或 D |
| 巢狀標籤失效 | level 設定不足 | 增加 tags 定義中的 level 值 |
| 變數 {$article.xxx} 顯示空白 | 查詢欄位名稱錯誤或資料為空 | 除錯 _article 回傳的 SQL、檢查資料表欄位 |
ThinkPHP 2.1 自定義標籤庫導入的最佳路徑:
@.Mylibs.Tag.TagLibTest 類別APP_AUTOLOAD_PATH => '@.Mylibs.Tag.'TAGLIB_PRE_LOAD => 'test'Runtime/ 快取<test:article> 無需 <tagLib> 宣告此方案零修改核心、相容性佳、維護容易,推薦用於所有 ThinkPHP 2.1 專案。