文档目录
模板语法规范

简介

本指南面向 DouPHP 的 DWT 模板语言,系统讲解变量输出、条件判断、循环遍历、函数调用(修饰器)、模板包含、URL 生成等核心语法;说明控制器如何向模板传递数据,以及如何在模板中访问数组、对象属性与方法;提供 HTML 组织与 SEO 建议;并给出调试技巧与常见问题解决方案。

更新 新增模板预过滤器机制说明,支持注释中的模板标签恢复和主题资源优化。

项目结构

DouPHP 的模板系统位于 core/web/template 下,采用"词法分析 → 语法分析 → 代码生成"的编译式流水线,运行时通过 RenderContext 暴露作用域与能力。模板资源支持 .dwt/.htm/.html/.tpl 扩展名,默认模板根目录为 templates,编译产物目录为 templates_c。

graph TB
A["模板源(.dwt/.htm/.html/.tpl)"] --> B["预过滤器(Prefilter)"]
B --> C["词法分析(Lexer)"]
C --> D["语法分析(Parser)"]
D --> E["代码生成(CodeGenerator)"]
E --> F["编译产物(PHP)"]
F --> G["运行期执行(RenderContext)"]

核心组件

  • 引擎入口:DouView,负责变量注入、渲染流程、编译缓存、安全校验与全局转义开关。
  • 编译器:DouViewCompiler,串联 Lexer → Parser → CodeGenerator,注册内置标签编译器。
  • 词法分析:Lexer,将模板源切分为 TokenStream,处理注释、literal/php 保护区与标签。
  • 语法分析:Parser,构建 AST,校验控制结构配对,收集文本块以还原空白。
  • 运行上下文:RenderContext,承载 $ctx->vars/$loops 等运行期状态,提供 includeTemplate、filter、loopProp 等方法。
  • 过滤器:FilterRegistry + StandardFilters,提供模板修饰器(如 |upper、|default 等)。
  • 标签注册表:TagCompilerRegistry,按节点类型分发到对应标签编译器。
  • 预过滤器:AdminPrefilter 和 FrontPrefilter,在模板编译前进行预处理,支持注释标签恢复和资源路径优化。

架构总览

下图展示从控制器到模板输出的完整链路:控制器通过门面或引擎实例 assign 变量,调用 fetch/display 渲染;引擎解析模板路径、按需编译、include 编译产物;运行期通过 $ctx 访问变量、调用修饰器、包含子模板。

sequenceDiagram
participant C as "控制器"
participant V as "DouView"
participant PF as "预过滤器"
participant CV as "DouViewCompiler"
participant L as "Lexer"
participant P as "Parser"
participant CG as "CodeGenerator"
participant R as "RenderContext"
C->>V : assign(变量)
C->>V : fetch("模板名")
V->>V : resolveTemplatePath()
V->>PF : apply(模板源码)
PF-->>V : 预处理后的源码
V->>CV : compile(资源名, 预处理源码)
CV->>L : tokenize(预处理源码)
L-->>CV : TokenStream
CV->>P : parse(TokenStream)
P-->>CV : AST + 文本块
CV->>CG : generate(AST, 文本块)
CG-->>V : PHP字符串
V->>V : include 编译产物
V->>R : 初始化上下文($ctx)
R-->>C : 输出HTML

详细组件分析

变量输出与作用域

  • 变量注入:通过引擎 assign 将变量放入作用域,模板中以 {$var} 形式输出。
  • 三元表达式:支持 {$a ? x : y} 与 {$a == 1 ? x : y} 等写法。
  • 修饰器:使用 | 管道符调用已注册的过滤器,如 {$name|upper}。
  • 自动转义:可通过 setEscapeHtml(true) 开启全局 HTML 转义。

条件判断 {if}/{elseif}/{else}/{/if}

  • 支持 if/elseif/else 分支,严格配对校验,未闭合会编译期报错。
  • 适合用于显示/隐藏区块、根据状态切换内容等场景。

循环遍历 {foreach}/{list}/{category}

  • 三种循环标签,均支持 else 段(当集合为空时渲染)。
  • 支持 break/continue 在循环体内使用(非 else 段)。
  • 支持 @ 属性:{$item@iteration/index/total/first/last/show}。
flowchart TD
Start(["进入循环"]) --> CheckEmpty{"集合是否为空?"}
CheckEmpty --> |是| ElseBranch["渲染 else 段"]
CheckEmpty --> |否| LoopBody["迭代项<br/>可访问 @ 属性"]
LoopBody --> Decision{"break/continue?"}
Decision --> |break| EndLoop["结束循环"]
Decision --> |continue| NextItem["下一项"]
Decision --> |无| LoopBody
ElseBranch --> EndLoop
NextItem --> LoopBody

赋值与局部变量 {assign}

  • 在模板内动态创建或覆盖变量,便于复用计算结果或中间值。
  • 运行期由 RenderContext.set 实现。

模板包含 {include}

  • 支持引入子模板,并可传入独立变量作用域,避免污染父作用域。
  • 支持捕获输出到变量(assignVar),便于组合片段。
  • 包含深度限制(默认 64)防止递归包含导致栈溢出。

URL 生成 {url}

  • 用于生成站点 URL,便于链接与跳转。

字面量与注释

  • {literal}...{/literal} 原样输出内部内容,不解析标签。
  • { ... } 注释,不参与输出。

定界符与分隔符

  • 支持自定义左右定界符(默认 { })。
  • 可使用 {ldelim} / {rdelim} 输出字面定界符。

控制器数据访问

  • 控制器通过引擎 assign 将数组/对象/方法返回值注入模板。
  • 模板中可直接访问数组键与对象属性,必要时结合修饰器进行格式化。
  • 示例参考后台视图中的变量输出与循环使用。

模板预过滤器

概述

模板预过滤器在模板编译前对源码进行处理,主要功能包括:

  • 注释中的模板标签恢复
  • 静态资源路径优化
  • 字符编码处理
  • 主题资源路径修正

后台预过滤器 (AdminPrefilter)

后台预过滤器专门处理 admin/view/ 目录下的模板文件,主要功能:

  1. 静态资源绝对化:将相对路径转换为绝对路径,确保在深路径(伪静态)环境下正常工作
  2. 注释标签恢复:智能识别并激活 HTML 注释中的模板标签
  3. 链接绝对化:处理硬编码的 index.php?route= 链接
// 注释标签恢复示例
<!-- {foreach $items as $item} -->
    <li>{$item.name}</li>
<!-- {/foreach} -->

章节来源

  • AdminPrefilter.php:35-57
  • AdminPrefilter.php:65-109

前台预过滤器 (FrontPrefilter)

前台预过滤器处理主题模板文件,主要功能:

  1. 主题路径解析:智能获取当前主题路径
  2. 资源路径修正:将相对路径转换为绝对主题路径
  3. 注释标签恢复:与后台保持一致的标签恢复逻辑
// 主题路径优先级
1. $GLOBALS['_THEME_PATH']
2. 分配的 theme_path 变量
3. 站点配置中的 site_theme

章节来源

  • FrontPrefilter.php:38-71
  • FrontPrefilter.php:79-123

预过滤器注册

预过滤器在应用启动时注册:

后台环境

$engine->registerPrefilter(array(AdminPrefilter::class, 'apply'));

前台环境

$engine->registerPrefilter(array(FrontPrefilter::class, 'apply'));

章节来源

  • Init.php (admin):195
  • Init.php (front):477

依赖关系分析

  • DouView 依赖 DouViewCompiler、CompileCache、RenderContext、FilterRegistry。
  • DouViewCompiler 依赖 Lexer、Parser、CodeGenerator、ExpressionCompiler、TagCompilerRegistry。
  • TagCompilerRegistry 集中注册各标签编译器(if/foreach/include/url/assign 等)。
  • RenderContext 依赖 FilterRegistry 提供修饰器能力。
  • 预过滤器:AdminPrefilter 和 FrontPrefilter 通过 registerPrefilter 注册到 DouView。
classDiagram
class DouView {
+assign()
+fetch()
+display()
+setEscapeHtml()
+registerPrefilter()
}
class DouViewCompiler {
+compile()
}
class Lexer {
+tokenize()
}
class Parser {
+parse()
+getTexts()
}
class CodeGenerator {
+generate()
}
class RenderContext {
+set()
+filter()
+includeTemplate()
+loopProp()
}
class TagCompilerRegistry {
+register()
+get()
}
class FilterRegistry {
+get()
}
class AdminPrefilter {
+apply()
+restoreCommentTags()
}
class FrontPrefilter {
+apply()
+restoreCommentTags()
}
DouView --> DouViewCompiler : "编译"
DouViewCompiler --> Lexer : "词法"
DouViewCompiler --> Parser : "语法"
DouViewCompiler --> CodeGenerator : "生成"
DouViewCompiler --> TagCompilerRegistry : "标签注册"
DouView --> RenderContext : "运行期"
RenderContext --> FilterRegistry : "修饰器"
DouView --> AdminPrefilter : "预过滤"
DouView --> FrontPrefilter : "预过滤"

性能考量

  • 编译缓存:基于版本头与修订号自动失效,减少重复编译开销。
  • 单次扫描词法:Lexer 采用单趟状态机,避免多次正则回溯。
  • 文本块保留:Parser 保留原文本序列,便于精确还原空白,降低渲染后格式抖动。
  • 包含深度限制:防止递归包含导致的性能与稳定性问题。
  • 预过滤器优化:预过滤器仅在编译阶段执行一次,不影响运行时性能。
  • 建议:
    • 合理拆分模板片段,避免过深嵌套。
    • 对大列表使用分页或懒加载,减少一次性渲染数据量。
    • 开启全局转义时注意性能影响,仅在需要时启用。
    • 合理使用预过滤器功能,避免过度复杂的预处理逻辑。

故障排查指南

  • 语法错误:Parser 会在编译期抛出异常,提示未闭合标签或不识别标签,定位到具体文件与行号。
  • 包含递归:超过最大包含深度会抛出异常,检查模板是否相互包含。
  • 变量未定义:确保控制器已通过 assign 注入变量;可在模板中使用默认修饰器提供回退值。
  • 输出乱码或转义异常:确认字符编码设置与全局转义开关;必要时使用 {literal} 包裹原始内容。
  • 循环 @ 属性无效:确认当前 item 变量名已在 loopVarmap 中映射,且处于有效循环上下文。
  • 预过滤器相关问题:
    • 注释标签未生效:检查注释格式是否正确,确保标签成对出现
    • 资源路径错误:确认主题路径配置正确,检查预过滤器是否正确注册
    • 后台/前台混淆:确认使用的是正确的预过滤器类

章节来源

  • Parser.php:386-397
  • RenderContext.php:153-159
  • AdminPrefilter.php:65-109
  • FrontPrefilter.php:79-123

结论

DouPHP 的 DWT 模板系统提供了清晰、可扩展的编译式模板语言。通过变量输出、条件判断、循环遍历、修饰器、模板包含与 URL 生成等能力,能够高效组织前端页面逻辑。新增的预过滤器机制进一步增强了模板处理能力,支持注释标签恢复和资源路径优化。配合合理的模板结构与 SEO 实践,可获得良好的可维护性与性能表现。

更新 预过滤器机制为模板开发提供了更强大的预处理能力,特别是在注释管理和资源优化方面。

附录:常用标签与用法速查

  • 变量输出:{$var}、三元 {$a ? x : y}
  • 条件判断:{if}{elseif}{else}{/if}
  • 循环遍历:{foreach}{/foreach}、{list}{/list}、{category}{/category},支持 else 段与 @ 属性
  • 赋值:{assign name="x" value="y"}
  • 包含:{include file="partial.dwt" vars=[]}
  • URL:{url path="/xxx"}
  • 字面量:{literal}...{/literal}
  • 注释:{ 注释 }
  • 定界符:{ldelim}、{rdelim}
  • 修饰器:{$var|filter:param}
  • 预过滤器注释:&lt;!-- {template_tag} --> 支持在HTML注释中使用模板标签

章节来源

  • Parser.php:135-243
  • RenderContext.php:87-140
  • DouViewCompiler.php:182-198
  • AdminPrefilter.php:45-54
  • FrontPrefilter.php:59-68

HTML结构组织与SEO优化

Bootstrap Icons集成

所有主题目录现已集成Bootstrap Icons CSS文件,提供丰富的图标资源:

<!-- 使用Bootstrap Icons -->
<i class="bi bi-house"></i>
<i class="bi bi-search"></i>
<i class="bi bi-gear"></i>

章节来源

  • bootstrap-icons.css:1-200

语义化标签使用

  • 使用 <header>、<nav>、<main>、<footer> 等语义化标签
  • 合理使用 <section>、<article>、<aside> 组织内容结构
  • 利用 <figure>、<figcaption> 描述图片和图表

SEO优化技巧

  • 合理使用 <title>、<meta description>、<meta keywords>
  • 使用 <h1>-<h6> 层级标题结构
  • 为图片添加 alt 属性
  • 使用结构化数据标记(Schema.org)
添加日期:2026-10-05