PHP 模板引擎完整教程
目录
- 为什么需要模板引擎? - 分离逻辑与展示
- 核心概念:MVC 模式
- 如何手动实现一个简单模板 - 理解原理
- 主流 PHP 模板引擎介绍
- 实战:使用 Twig 模板引擎
- 安装与配置
- 变量输出
- 控制结构 (if, for)
- 模板继承与包含
- 过滤器
- 最佳实践与总结
为什么需要模板引擎?
在学习模板引擎之前,我们先来看一个没有使用模板的坏例子:

坏例子:逻辑和视图混在一起 (index.php)
<?php
// 数据库查询等逻辑
$users = [
['name' => '张三', 'age' => 25, 'is_active' => true],
['name' => '李四', 'age' => 30, 'is_active' => false],
['name' => '王五', 'age' => 28, 'is_active' => true],
];
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">用户列表</title>
</head>
<body>
<h1>用户列表</h1>
<table border="1">
<tr>
<th>姓名</th>
<th>年龄</th>
<th>状态</th>
</tr>
<?php foreach ($users as $user): ?>
<tr>
<td><?php echo htmlspecialchars($user['name']); ?></td>
<td><?php echo $user['age']; ?></td>
<td><?php echo $user['is_active'] ? '在线' : '离线'; ?></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>
这个坏例子有什么问题?
- 难以维护:PHP 代码和 HTML 代码混在一起,当页面布局需要修改时,很容易误伤 PHP 逻辑。
- 前端开发困难:前端工程师无法直接修改 HTML,因为他们不熟悉 PHP 语法和
echo语句。 - 不安全:忘记使用
htmlspecialchars()会导致 XSS (跨站脚本) 攻击漏洞,虽然例子中写了,但在大型项目中很容易遗漏。 - 代码复用性差:如果想在另一个页面显示用户列表,需要复制粘贴一大段 HTML 和 PHP 代码。
解决方案:模板引擎
模板引擎的作用就是将 业务逻辑 (PHP) 和 页面展示 (HTML) 分离。

- PHP 文件 (控制器):负责处理数据、调用数据库、进行业务判断。
- 模板文件 (视图):只负责展示数据,语法更接近 HTML,易于前端人员修改。
核心概念:MVC 模式
模板引擎是 MVC (Model-View-Controller) 设计模式中的关键一环。
- Model (模型):负责数据和业务逻辑,比如数据库操作。
- View (视图):负责用户界面展示,就是我们的模板文件。
- Controller (控制器):作为 Model 和 View 之间的桥梁,接收用户请求,调用 Model 获取数据,然后将数据传递给 View 进行渲染。
在这个模式中,PHP 代码(Controller)只负责准备数据,而模板(View)只负责显示数据。
如何手动实现一个简单模板(理解原理)
为了更好地理解模板引擎的工作,我们手动实现一个最简单的版本。
步骤 1:创建模板文件 template.html
使用特殊的占位符 {{变量名}} 来标记需要替换的内容。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">{{page_title}}</title>
</head>
<body>
<h1>{{header_text}}</h1>
<p>{{content}}</p>
</body>
</html>
步骤 2:创建 PHP 文件 render.php 来解析模板
<?php
// 1. 准备数据
$data = [
'page_title' => '我的第一个模板',
'header_text' => '欢迎!',
'content' => '这是一个通过简单模板引擎渲染的页面。'
];
// 2. 读取模板文件内容
$templateContent = file_get_contents('template.html');
// 3. 替换占位符
// 使用 preg_replace 进行简单的替换
foreach ($data as $key => $value) {
// 使用 preg_quote 转义正则特殊字符,防止变量名包含特殊字符导致错误
$pattern = '/{{' . preg_quote($key, '/') . '}}/';
$replacement = htmlspecialchars($value); // 自动进行转义,防止XSS
$templateContent = preg_replace($pattern, $replacement, $templateContent);
}
// 4. 输出最终HTML
echo $templateContent;
?>
运行 render.php,你将得到:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">我的第一个模板</title>
</head>
<body>
<h1>欢迎!</h1>
<p>这是一个通过简单模板引擎渲染的页面。</p>
</body>
</html>
这个简单的例子展示了模板引擎的核心思想:替换占位符,专业的模板引擎功能强大得多,比如循环、条件判断、模板继承等。
主流 PHP 模板引擎介绍
手动实现只适合理解原理,实际项目中应使用成熟的模板引擎。
| 引擎名称 | 特点 | 官网 |
|---|---|---|
| Twig | 强烈推荐,功能强大、安全(默认自动转义)、语法清晰、性能优秀、有良好的文档和社区支持,是现代 PHP 项目的首选。 | twig.symfony.com |
| Blade (Laravel) | Laravel 框架内置,非常简洁,结合了 PHP 原生语法,对 Laravel 开发者极其友好,如果不用 Laravel,单独使用稍显笨重。 | laravel.com/docs/blade |
| Smarty | 老牌模板引擎,功能非常全面,有自己的语法规则,与 PHP 语法分离度最高,但因其语法复杂和性能问题,在新项目中已不常用。 | www.smarty.net |
| Latte | 来自 Nette 框架,以安全性著称(自动转义、沙箱模式),语法优雅,性能极佳,是另一个非常优秀的选择。 | latte.nette.org |
本教程将以最推荐的 Twig 为例进行实战讲解。
实战:使用 Twig 模板引擎
1 安装与配置
使用 Composer 是最简单的方式。
-
安装 Composer:如果你还没有安装,请先去 getcomposer.org 下载安装。
-
创建项目并安装 Twig: 在你的项目根目录下创建一个
composer.json文件,或者直接在命令行运行:# 创建一个新目录并进入 mkdir my-twig-project cd my-twig-project # 初始化 Composer 项目 composer init -n # 安装 Twig composer require "twig/twig:^3.0"
-
创建 PHP 文件
index.php并配置 Twig:<?php // 引入 Composer 的自动加载器 require 'vendor/autoload.php'; // 使用 Twig命名空间 use Twig\Environment; use Twig\Loader\FilesystemLoader; // 1. 指定模板文件夹的路径 $loader = new FilesystemLoader('templates'); // 2. 初始化 Twig 环境 // - cache: 设置模板编译缓存目录,能极大提升性能,生产环境务必开启。 // - auto_reload: 当模板文件修改后,Twig 是否自动重新编译。 $twig = new Environment($loader, [ 'cache' => false, // 开发环境可以设为 false,生产环境设为 'cache' 目录 'auto_reload' => true, ]); // 3. 准备要传递给模板的数据 $data = [ 'page_title' => '用户列表 (Twig版)', 'users' => [ ['name' => '张三', 'age' => 25, 'is_active' => true], ['name' => '李四', 'age' => 30, 'is_active' => false], ['name' => '王五', 'age' => 28, 'is_active' => true], ] ]; // 4. 加载模板并渲染 // 'user_list.html' 是模板文件名,不需要后缀 // 第二个参数是传递给模板的数据 echo $twig->render('user_list.html', $data); ?>
2 创建模板文件 templates/user_list.html
在你的项目根目录下创建 templates 文件夹,并在其中创建 user_list.html。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">{{ page_title }}</title>
<style>
table { border-collapse: collapse; width: 50%; }
th, td { border: 1px solid #cccccc; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>{{ page_title }}</h1>
<table>
<thead>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{# 这是一个 Twig 的注释,不会出现在最终HTML中 #}
{% for user in users %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.age }}</td>
<td>
{# 使用 if 判断 #}
{% if user.is_active %}
<span style="color: green;">在线</span>
{% else %}
<span style="color: red;">离线</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
运行 index.php,你会看到一个漂亮的、安全的用户列表页面。 注意,我们直接写了 {{ user.name }},但 Twig 默认会自动进行 HTML 转义,防止了 XSS 攻击。
3 模板继承与包含
这是模板引擎的另一个强大功能,可以复用通用的页面布局(如头部、底部)。
创建基础布局模板 templates/base.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">{% block title %}默认标题{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
<header>
<h1>我的网站</h1>
<nav>
<ul>
<li><a href="/">首页</a></li>
<li><a href="/about">lt;/a></li>
</ul>
</nav>
</header>
<main>
{# 这个块将被子模板填充内容 #}
{% block content %}{% endblock %}
</main>
<footer>
<p>© 2025 我的网站</p>
</footer>
{% block javascripts %}{% endblock %}
</body>
</html>
修改 user_list.html 使其继承 base.html
{# 继承基础布局 #}
{% extends "base.html" %}
{# 覆盖基础布局中的 title 块 #}
{% block title %}{{ page_title }}{% endblock %}
{# 在基础布局的 stylesheets 块中添加自己的样式 #}
{% block stylesheets %}
<style>
table { border-collapse: collapse; width: 50%; }
th, td { border: 1px solid #cccccc; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
{% endblock %}
{# 覆盖基础布局中的 content 块 #}
{% block content %}
<h1>{{ page_title }}</h1>
<table>
<!-- ... 表格内容保持不变 ... -->
</table>
{% endblock %}
user_list.html 的内容会自动嵌入到 base.html 的 {% block content %} 中,并且可以自定义标题和样式。
4 过滤器
过滤器可以修改变量在显示前的值,用 符号连接。
{# 将字符串转为大写 #}
<p>{{ "hello world" | upper }}</p> {# 输出: HELLO WORLD #}
{# 格式化日期 #}
<p>{{ some_date | date("Y-m-d H:i:s") }}</p>
{# 只取数组的前3个元素 #}
<p>{{ my_array | slice(0, 3) | join(', ') }}</p>
{# 链式使用过滤器 #}
<p>{{ " some text " | trim | upper }}</p> {# 输出: SOME TEXT #}
最佳实践与总结
- 永远分离逻辑和视图:你的 PHP 文件(控制器)只应该做数据处理、业务逻辑判断,然后调用
$twig->render(),模板里不应该有复杂的 PHP 逻辑。 - 利用模板继承:创建一个
base.html作为所有页面的基础,然后让具体页面继承它,这能极大提高代码复用性和维护性。 - 保持简洁:不要在模板里写复杂的循环或判断,如果逻辑太复杂,应该把它放到控制器或模型中,然后将处理好的简单数据(如布尔值、格式化好的字符串)传递给模板。
- 信任你的数据:使用像 Twig 这样默认开启自动转义的模板引擎,你就不需要再手动为每个变量写
htmlspecialchars(),如果某个变量是安全的(比如你明确知道它不包含 HTML),可以使用|raw过滤器:{{ my_safe_var | raw }}。 - 开启缓存:在生产环境中,务必为 Twig 设置
cache目录,Twig 会将模板编译成 PHP 缓存文件,下次渲染时直接加载缓存,速度会快很多。
通过学习本教程,你应该已经掌握了 PHP 模板引擎的核心思想、优势以及如何使用主流的 Twig 引擎进行开发,这会让你的 PHP 项目更加健壮、安全、易于维护和协作。
