ThinkPHP 的模板引擎(默认是 Think\Template)设计初衷是为了分离 PHP 逻辑和 HTML 视图,让前端开发者能够更容易地修改页面,而无需接触复杂的 PHP 代码,它鼓励使用模板标签来代替原生 PHP 代码。

thinkphp 模板 php代码
(图片来源网络,侵删)

ThinkPHP 也提供了在模板中直接嵌入 PHP 代码的能力,以应对一些复杂或特殊的逻辑需求。

下面我将从推荐做法不推荐做法,再到核心原理,为你详细解析。


推荐做法:使用模板标签(最佳实践)

这是 ThinkPHP 模板设计的核心,也是你应该优先使用的方式,模板标签语法简单,可读性强,并且经过了模板引擎的安全处理。

输出变量

这是最常用的功能。

thinkphp 模板 php代码
(图片来源网络,侵删)
// 在 PHP 控制器中分配变量
$this->assign('name', 'ThinkPHP');
$this->assign('user', ['id' => 1, 'username' => 'zhangsan']);

在模板文件 index.html 中:

<!DOCTYPE html>
<html>
<head>ThinkPHP 模板示例</title>
</head>
<body>
    <h1>Hello, {$name}!</h1>
    <p>用户ID: {$user.id}</p>
    <p>用户名: {$user.username}</p>
    <!-- 使用默认值 -->
    <p>年龄: {$user.age|default:18}</p>
</body>
</html>
  • {$name}: 输出普通变量。
  • {$user.id}: 输出关联数组(或对象)的元素。
  • {$user.age|default:18}: user.age 不存在或为空,则输出默认值 18

使用函数

可以对变量进行简单的函数处理。

// 控制器
$this->assign('content', 'hello world');
<p>原文: {$content}</p>
<p>转为大写: {:strtoupper($content)}</p>
<p>首字母大写: {:ucwords($content)}</p>
  • {:function($var)}: 表示执行函数并输出结果。

条件判断 if / elseif / else

// 控制器
$this->assign('status', 1); // 1: 已发布, 0: 草稿
$this->assign('score', 85);
{if $status eq 1}
    <p style="color: green;">文章已发布</p>
{elseif $status eq 0}
    <p style="color: orange;">文章为草稿</p>
{else /}
    <p>状态未知</p>
{/if}
<br>
{if $score >= 90}
    <p>优秀!</p>
{else /}
    <p>继续努力!</p>
{/if}
  • eq: 等于
  • neq: 不等于
  • gt: 大于
  • lt: 小于
  • egt: 大于等于
  • elt: 小于等于
  • mod: 取模

循环输出 volist / for

volist 用于遍历数组:

// 控制器
$this->assign('list', [
    ['id' => 1, 'name' => '苹果'],
    ['id' => 2, 'name' => '香蕉'],
    ['id' => 3, 'name' => '橙子'],
]);
<ul>
    {volist name="list" id="vo" key="k"}
        <li>
            索引: {$k} - ID: {$vo.id} - 名称: {$vo.name}
        </li>
    {/volist}
</ul>
  • name: 要遍历的变量名。
  • id: 循环中每个元素的临时变量名。
  • key: 循环的索引(键名),可选。

for 用于数字循环:

thinkphp 模板 php代码
(图片来源网络,侵删)
{for start="1" end="10" step="2" name="i"}
    <p>当前数字: {$i}</p>
{/for}

模板包含 include

用于引入其他模板文件,实现模块化。

假设有一个公共头部模板 public/header.html

<!-- public/header.html -->
<header>
    <h1>网站头部</h1>
</header>

在主模板 index.html 中:

{include file="public/header" /}
<main>
    <!-- 页面主要内容 -->
</main>
{include file="public/footer" /}

不推荐做法:直接使用 PHP 代码

虽然 ThinkPHP 允许在模板中写原生 PHP,但这会破坏模板的初衷,导致视图层逻辑混乱,不利于维护,请谨慎使用。

输出 PHP 代码

这个标签在上面已经提过,用于执行单行 PHP 代码并输出结果。

// 控制器
$this->assign('time', time());
<p>当前时间戳: {:time()}</p>
<p>格式化时间: {:date('Y-m-d H:i:s', $time)}</p>

执行 PHP 代码 {php}

用于执行一段 PHP 代码,但不直接输出结果。

{php}
    $a = 10;
    $b = 20;
    $sum = $a + $b;
{/php}
<p>计算结果: {$sum}</p> 
<!-- 注意:$sum 变量需要在 {php} 块外部定义才能被模板识别 -->

更规范的做法(不推荐但可行):

{php}
    $a = 10;
    $b = 20;
    $sum = $a + $b;
    // 将结果赋值给一个模板变量
    $this->assign('sum', $sum);
{/php}
<p>计算结果: {$sum}</p>

使用原生 PHP 标签 <?php ?>

ThinkPHP 默认是开启原生 PHP 标签支持的,但强烈建议关闭,因为它完全失去了模板引擎的意义。

如果你确实需要,并且配置文件 config/template.php 中的 'php_support' => true,那么你可以这样写:

<?php
    $userList = [ ... ]; // 复杂的数组构建逻辑
    foreach ($userList as $user) {
        // ... 循环处理
    }
?>
<div>
    <?php foreach ($userList as $u): ?>
        <p><?php echo $u['name']; ?></p>
    <?php endforeach; ?>
</div>

为什么强烈不推荐?

  • 逻辑耦合:视图层包含了大量业务逻辑,违反了 MVC 分离原则。
  • 可读性差:对于前端开发者不友好。
  • 安全性:如果模板文件可以被用户上传,原生 PHP 标签会带来巨大的安全风险(如代码注入)。

核心原理:模板如何解析 PHP 代码?

当你使用模板标签(如 {$name})时,ThinkPHP 的模板引擎在后台做了以下事情:

  1. 编译:当模板文件第一次被请求时,模板引擎会读取 index.html 文件。
  2. 替换:引擎会将模板标签替换成原生的 PHP 代码。
    • {$name} 会被编译成 <?php echo $name; ?>
    • {if $status eq 1} 会被编译成 <?php if ($status == 1): ?>
    • {volist name="list" id="vo"} 会被编译成 <?php foreach($list as $vo): ?>
  3. 生成缓存:编译后的 PHP 代码会被保存到一个缓存文件(Runtime/cache/编译后文件名.php)中。
  4. 执行:后续请求该模板时,如果模板源文件没有修改,ThinkPHP 会直接执行这个缓存文件,从而大大提高了运行效率。

当你使用 {php}<?php ?> 标签时,模板引擎会跳过编译和替换步骤,直接将你写的 PHP 代码原样复制到最终的缓存文件中执行。


总结与最佳实践

方法 语法 推荐度 说明
变量输出 {$var} ⭐⭐⭐⭐⭐ 首选,简洁安全
函数调用 {:function($var)} ⭐⭐⭐⭐⭐ 首选,用于简单逻辑处理
条件判断 {if}...{elseif}...{else}{/if} ⭐⭐⭐⭐⭐ 首选,逻辑清晰
循环输出 {volist}, {for} ⭐⭐⭐⭐⭐ 首选,专门为遍历设计
模板包含 {include file="..."} ⭐⭐⭐⭐⭐ 首选,代码复用
PHP 代码块 {php}...{/php} 谨慎使用,用于无法用标签实现的复杂逻辑
原生 PHP <?php ... ?> 强烈不推荐,破坏 MVC 结构,带来安全隐患

核心思想:将尽可能多的逻辑放在控制器或模型中处理,只将最简单的数据展示和循环逻辑放在模板中,如果发现模板中的逻辑越来越复杂,就应该反思是否将过多的业务逻辑放到了视图层。