核心原则:MVC 模式
无论你采用哪种具体方法,其背后都遵循着 MVC (Model-View-Controller) 设计思想:

(图片来源网络,侵删)
- Model (模型): 负责数据和业务逻辑,它处理数据库交互、数据验证、计算等。这部分代码应该是与模板无关的。
- View (视图): 负责展示,就是你的HTML模板文件,里面可以包含一些简单的逻辑(如
if/else,foreach)来格式化数据,但不应该包含复杂的业务处理。 - Controller (控制器): 作为Model和View之间的协调者,它接收用户请求,调用Model获取数据,然后将数据传递给View进行渲染,最后将渲染好的HTML响应给用户。
我们的目标就是让一个Controller能够根据不同情况,调用不同的View(模板)。
简单的 if/else 或 switch 语句 (不推荐,但作为起点)
对于只有两三个模板且逻辑非常简单的情况,你可能会在控制器里直接判断。
示例:
// file: index.php
$template = 'template_a.php'; // 默认模板
if (isset($_GET['theme']) && $_GET['theme'] === 'modern') {
$template = 'template_b.php';
}
// 1. 获取数据 (Model部分)
$products = getProductsFromDatabase();
// 2. 将数据传递给模板 (准备View)
include $template;
问题所在:

(图片来源网络,侵删)
- 违反单一职责原则:控制器既要处理业务逻辑,又要负责选择视图,代码臃肿。
- 难以扩展:每增加一个模板,都要修改控制器代码,非常不灵活。
- 维护困难:当模板变多时,
if/else链条会变得非常长,难以管理。
适用场景:几乎不推荐用于生产环境,仅适用于个人快速原型开发。
基于路由的模板加载 (推荐)
这是最常用、最基础的管理方法,核心思想是:不同的URL路径(路由)对应不同的控制器和模板。
目录结构示例:
project/
├── controllers/
│ ├── HomeController.php
│ ├── ProductController.php
│ └── AboutController.php
├── models/
│ └── ProductModel.php
├── views/
│ ├── layouts/
│ │ └── main.php // 公共布局
│ ├── home/
│ │ ├── index.php // 首页模板
│ │ └── about.php // 关于我们页面
│ └── products/
│ └── list.php // 产品列表模板
├── index.php // 前端控制器
└── .htaccess // URL重写
实现步骤:

(图片来源网络,侵删)
-
.htaccess:将所有非文件请求重定向到index.php。RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?url=$1 [QSA,L] -
index.php(前端控制器):解析URL,加载对应的控制器。// index.php $url = isset($_GET['url']) ? rtrim($_GET['url'], '/') : ''; $urlSegments = explode('/', $url); $controllerName = !empty($urlSegments[0]) ? ucfirst($urlSegments[0]) . 'Controller' : 'HomeController'; $methodName = !empty($urlSegments[1]) ? $urlSegments[1] : 'index'; $params = array_slice($urlSegments, 2); // 检查控制器文件是否存在 if (file_exists("controllers/{$controllerName}.php")) { require_once "controllers/{$controllerName}.php"; $controller = new $controllerName(); // 检查方法是否存在 if (method_exists($controller, $methodName)) { call_user_func_array([$controller, $methodName], $params); } else { // 处理404 echo "Method not found"; } } else { // 处理404 echo "Controller not found"; } -
控制器:每个控制器负责一个模块,其方法负责加载对应的模板。
// controllers/HomeController.php class HomeController { public function index() { // 1. 获取数据 $pageTitle = "欢迎来到首页"; $featuredProducts = []; // 从模型获取数据 // 2. 准备模板数据 $data = [ 'title' => $pageTitle, 'products' => $featuredProducts ]; // 3. 加载视图 $this->loadView('home/index', $data); } public function about() { $data = ['title' => '关于我们']; $this->loadView('home/about', $data); } // 辅助方法:加载视图 private function loadView($viewName, $data = []) { // 将数据变量解压到当前符号表,这样模板里可以直接用 $title extract($data); // 包含布局文件 require_once 'views/layouts/main.php'; } } -
视图:模板文件只负责展示。
// views/layouts/main.php <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title><?php echo $title; ?></title> </head> <body> <header>网站头部</header> <main> <?php // 这里是具体的内容页面 require_once "views/{$viewName}.php"; ?> </main> <footer>网站底部</footer> </body> </html>
优点:
- 结构清晰:URL、控制器、视图一一对应,易于理解和维护。
- 可扩展性强:新增页面只需新建控制器和视图文件,无需修改现有代码。
- 符合MVC思想:职责分离得比较好。
使用模板引擎 (更高级的推荐)
当网站变得复杂,PHP原生模板的语法(<?php echo $variable; ?>)会显得笨重且不安全(容易遭受XSS攻击),这时,使用专门的模板引擎是更好的选择。
流行的PHP模板引擎有:Twig, Smarty, Blade (Laravel内置) 等。
这里以 Twig 为例,因为它现代、安全且功能强大。
实现步骤:
-
安装Twig:使用Composer。
composer require "twig/twig:^3.0"
-
修改控制器:在控制器中,不再使用
include,而是使用Twig来渲染模板。// controllers/HomeController.php require_once __DIR__ . '/../vendor/autoload.php'; class HomeController { private $twig; public function __construct() { // 初始化Twig环境 $loader = new \Twig\Loader\FilesystemLoader(__DIR . '/../views'); $this->twig = new \Twig\Environment($loader, [ 'cache' => false, // 生产环境应设置为缓存目录,如 __DIR__ . '/../cache' 'debug' => true, ]); } public function index() { // 1. 获取数据 $pageTitle = "欢迎来到首页 (Twig版)"; $featuredProducts = [ ['name' => '产品A', 'price' => 100], ['name' => '产品B', 'price' => 200], ]; // 2. 渲染模板并直接输出 echo $this->twig->render('home/index.html.twig', [ 'title' => $pageTitle, 'products' => $featuredProducts ]); } } -
修改视图:使用Twig的简洁、安全语法。
{# views/home/index.html.twig #} <!DOCTYPE html> <html> <head> <title>{{ title }}</title> </head> <body> <h1>{{ title }}</h1> <ul> {% for product in products %} <li>{{ product.name }} - ¥{{ product.price }}</li> {% else %} <li>暂无产品</li> {% endfor %} </ul> </body> </html>
优点:
- 语法简洁:
{{ variable }}和{% logic %}比PHP标签更易
