PHP 模板引擎完整教程

目录

  1. 为什么需要模板引擎? - 分离逻辑与展示
  2. 核心概念:MVC 模式
  3. 如何手动实现一个简单模板 - 理解原理
  4. 主流 PHP 模板引擎介绍
  5. 实战:使用 Twig 模板引擎
    • 安装与配置
    • 变量输出
    • 控制结构 (if, for)
    • 模板继承与包含
    • 过滤器
  6. 最佳实践与总结

为什么需要模板引擎?

在学习模板引擎之前,我们先来看一个没有使用模板的坏例子:

php 模板 教程
(图片来源网络,侵删)

坏例子:逻辑和视图混在一起 (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>

这个坏例子有什么问题?

  1. 难以维护:PHP 代码和 HTML 代码混在一起,当页面布局需要修改时,很容易误伤 PHP 逻辑。
  2. 前端开发困难:前端工程师无法直接修改 HTML,因为他们不熟悉 PHP 语法和 echo 语句。
  3. 不安全:忘记使用 htmlspecialchars() 会导致 XSS (跨站脚本) 攻击漏洞,虽然例子中写了,但在大型项目中很容易遗漏。
  4. 代码复用性差:如果想在另一个页面显示用户列表,需要复制粘贴一大段 HTML 和 PHP 代码。

解决方案:模板引擎

模板引擎的作用就是将 业务逻辑 (PHP)页面展示 (HTML) 分离。

php 模板 教程
(图片来源网络,侵删)
  • 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 是最简单的方式。

  1. 安装 Composer:如果你还没有安装,请先去 getcomposer.org 下载安装。

  2. 创建项目并安装 Twig: 在你的项目根目录下创建一个 composer.json 文件,或者直接在命令行运行:

    # 创建一个新目录并进入
    mkdir my-twig-project
    cd my-twig-project
    # 初始化 Composer 项目
    composer init -n
    # 安装 Twig
    composer require "twig/twig:^3.0"
  3. 创建 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>&copy; 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 #}

最佳实践与总结

  1. 永远分离逻辑和视图:你的 PHP 文件(控制器)只应该做数据处理、业务逻辑判断,然后调用 $twig->render(),模板里不应该有复杂的 PHP 逻辑。
  2. 利用模板继承:创建一个 base.html 作为所有页面的基础,然后让具体页面继承它,这能极大提高代码复用性和维护性。
  3. 保持简洁:不要在模板里写复杂的循环或判断,如果逻辑太复杂,应该把它放到控制器或模型中,然后将处理好的简单数据(如布尔值、格式化好的字符串)传递给模板。
  4. 信任你的数据:使用像 Twig 这样默认开启自动转义的模板引擎,你就不需要再手动为每个变量写 htmlspecialchars(),如果某个变量是安全的(比如你明确知道它不包含 HTML),可以使用 |raw 过滤器:{{ my_safe_var | raw }}
  5. 开启缓存:在生产环境中,务必为 Twig 设置 cache 目录,Twig 会将模板编译成 PHP 缓存文件,下次渲染时直接加载缓存,速度会快很多。

通过学习本教程,你应该已经掌握了 PHP 模板引擎的核心思想、优势以及如何使用主流的 Twig 引擎进行开发,这会让你的 PHP 项目更加健壮、安全、易于维护和协作。