DedeCMS 的标签系统本质上是一个模板引擎,它的核心任务是将模板文件(.htm)中定义的特定标签(如 {dede:arclist})替换成由 PHP 代码动态生成的实际内容(如文章列表)。

核心解析类:DedeTagParse
在 DedeCMS 的早期版本(如 5.x)中,核心的标签解析类是 DedeTagParse,它位于 /include/dedetag.class.php 文件中,这个类负责读取模板,识别标签,调用相应的处理函数,并最终输出解析后的 HTML。
在 DedeCMS 5.7 及以后的版本中,为了提高性能和灵活性,引入了新的解析引擎 ArcPartView.class.php,它内部会使用 DedeTag 类(注意不是 DedeTagParse)来进行更高效的标签解析,但 DedeTagParse 的逻辑依然是理解整个系统的基础。
标签解析的基本流程
无论是 DedeTagParse 还是 ArcPartView,其解析流程都遵循以下步骤:
- 读取模板:解析器首先读取模板文件的内容,得到一个包含 HTML 和标签的字符串。
- 识别标签:解析器会遍历这个字符串,根据特定的模式(如
{dede:...})来识别出所有的 DedeCMS 标签。 - 参数分离:对于识别出的标签,解析器会将其拆分为标签名和参数,在
{dede:arclist titlelen='30' row='10'}中,标签名是arclist,参数是titlelen='30'和row='10'。 - 函数调用:解析器会根据标签名,去一个预定义的“标签库”中查找对应的处理函数(PHP 函数)。
- 数据处理:调用找到的 PHP 函数,并将解析出的参数传递给它,这个函数会连接数据库,查询数据,并进行格式化处理。
- 内容替换:函数处理完毕后,会返回一个字符串(即要替换的内容),解析器会用这个返回的字符串替换掉原始模板中的那个标签。
- 循环与嵌套:如果标签是循环型的(如
arclist),步骤 4-6 会在循环中执行,直到所有数据项都被处理完毕,如果标签是嵌套的(如channel中嵌套arclist),解析器会递归地处理内部标签。 - 最终输出:当模板中所有标签都被解析完毕后,解析器会输出最终的、纯 HTML 的内容。
核心类详解:DedeTagParse.class.php
让我们深入看一下 /include/dedetag.class.php 文件中的关键部分。

属性
class DedeTagParse {
var $sourceString = ''; // 待解析的模板字符串
var $refObj = null; // 引用的对象,通常是环境变量容器
var $cTF = array(); // 标签配置,存储标签名和对应的处理函数
var $buildCache = array(); // 构建缓存,用于存储已经解析过的标签结果
// ... 其他属性
}
sourceString:存放从模板文件中读取的原始内容。refObj:一个非常关键的属性,它是一个对象,包含了当前页面的所有环境变量,如typeid(栏目ID)、aid(文章ID)等,标签处理函数需要通过这个对象来获取上下文信息。cTF:标签函数映射表,是整个解析系统的“字典”,它定义了哪个标签名对应哪个 PHP 函数。
关键方法
LoadTemplate($filename)
此方法用于加载模板文件。
function LoadTemplate($filename) {
// 读取文件内容到 $this->sourceString
$this->sourceString = file_get_contents($filename);
// ... 其他初始化操作
}
Parse()
这是解析器的“引擎”,是整个类的心脏,它会调用 ParseOne() 来处理每一个标签。
function Parse() {
// 主循环,不断查找并替换标签,直到没有标签为止
while($this->CTags = $this->GetTag("CTag")) {
$this->ParseCTag();
}
// ... 处理其他类型的标签
return $this->sourceString;
}
GetTag($type) 和 ParseCTag()
这两个是内部的核心方法。
GetTag():负责在sourceString中查找下一个指定类型的标签(如CTag,即普通标签{dede:...}),并将其信息(标签名、属性、位置等)存入CTags属性中。ParseCTag():当找到一个标签后,此方法被调用,它会:- 从
CTags中获取标签名和参数。 - 根据标签名,在
cTF数组中查找对应的处理函数名。 - 如果找到函数,则调用该函数,并传入参数和
refObj对象。 - 用函数的返回值替换掉
sourceString中的原始标签。
- 从
标签是如何“注册”的?
一个标签(如 arclist)之所以能被解析,是因为它的处理函数已经在 cTF 数组中被定义了,这个注册过程通常在 DedeCMS 的入口文件或核心类中完成。

以 arclist 标签为例,它的处理函数是 lib_arclist.php 文件中的 Arclist() 函数,注册过程大致如下:
// 在某个初始化文件中 $dp = new DedeTagParse(); // 将标签名 'arclist' 和它的处理函数 'Arclist' 关联起来 $dp->cTF['arclist'] = 'Arclist'; // ... 注册其他标签
lib_arclist.php 中的 Arclist() 函数是真正的数据生成器,它接收参数(如 titlelen, row),执行 SQL 查询获取文章列表,然后使用 GetResult() 等函数将数据格式化成 HTML 字符串返回给解析器。
一个完整的例子:{dede:arclist}
让我们追踪 arclist 标签的完整生命周期:
- 模板文件:你的模板文件
index.htm中有{dede:arclist row='5' titlelen='20'}[/dede:arclist]。 - 加载:PHP 代码加载
index.htm被读入DedeTagParse对象的sourceString。 - 解析:
Parse()方法被调用。 - 识别:
GetTag()找到{dede:arclist ...},提取出标签名arclist和参数row='5',titlelen='20'。 - 查找函数:
ParseCTag()在cTF中查找arclist,发现它对应lib_arclist.php中的Arclist函数。 - 调用函数:
ParseCTag()调用Arclist($refObj, $ctag),$refObj包含了当前页面的环境变量(如首页的typeid=0),$ctag包含了row和titlelen参数。 - 数据处理:
Arclist()函数内部:- 根据
$refObj->typeid和$ctag->GetAtt('row')等参数构建 SQL 查询。 - 执行查询,获取5篇文章的标题、链接等信息。
- 循环这5篇文章,为每篇文章生成一个
<li>标签,如<li><a href="文章链接">文章标题</a></li>。 - 将所有
<li>拼接成一个完整的 HTML 字符串。
- 根据
- 内容替换:
ParseCTag()将返回的 HTML 字符串替换掉{dede:arclist ...}。 - 最终输出:解析完成后,
sourceString中不再有 DedeCMS 标签,只剩下纯 HTML,这个 HTML 最终被发送到用户的浏览器。
| 组件 | 作用 | 关键文件/类 |
|---|---|---|
模板中的占位符,如 {dede:arclist} |
模板文件 (.htm) |
|
| 解析器 | 读取模板,识别标签,并调用相应函数 | DedeTagParse, ArcPartView |
| 标签库 | 定义标签名与处理函数的映射关系 | 在核心代码中动态注册 |
| 处理函数 | 真正执行数据库查询、数据处理和HTML生成的PHP函数 | lib_*.php (如 lib_arclist.php) |
| 环境变量 | 提供当前页面的上下文信息(如栏目ID) | refObj 对象 |
理解了 DedeTagParse 的工作原理,你就能明白:
- 如何自定义标签:只需编写一个处理函数,并在标签库中注册即可。
- 为什么标签不生效:可能是标签名写错了、函数不存在、参数错误或数据库查询无数据。
- 如何优化性能:可以通过开启缓存机制,避免重复解析和查询数据库。
