首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

MVC 模式在 PHP 中的落地實踐:從核心概念到自建框架完整思路

     編輯:PHP 相關知識

MVC(Model-View-Controller)是 Web 應用最經典的架構模式。本文不談具體框架,而是從「為什麼需要 MVC」「核心職責劃分」「PHP 自建 MVC 最小骨架」「請求生命週期」「常見誤區與演進方向」五個維度,幫你建立可遷移的架構思維。

為什麼需要 MVC?

痛點無 MVC(單腳本)有 MVC
代碼組織所有邏輯塞在 page.php,千行巨石職責分離,檔案小、易定位
維護性改樣式怕動 SQL,改邏輯怕壞 HTML修改 View 不動 Model,改 Model 不動 Controller
複用性複製貼上,Bug 同步傳播Model/Service 複用,Controller 組合
測試性難以單元測試Model/Service 可獨立測試,Controller 可 Mock
團隊協作衝突不斷,無法並行前後端分離,後端並行開發不同 Module

MVC 三層職責鐵律

  • Model(模型):資料存取、業務規則、領域邏輯。**不含** HTTP 請求參數、模板渲染、Session 操作。
  • View(視圖):呈現邏輯、模板渲染、格式化輸出。**不含** SQL、業務決策、資料獲取(僅接收 Controller 傳入的資料)。
  • Controller(控制器):請求入口、參數驗證、協調 Model/View、回傳 Response。**不含** SQL、HTML 拼接、複雜業務計算(委託 Service/Model)。

PHP 自建 MVC 最小骨架(教學級)

目錄結構


app/
├── Core/                    # 核心基類
│   ├── Application.php      # 應用啟動、路由分發
│   ├── Controller.php       # Controller 基類
│   ├── Model.php            # Model 基類(含 DB 連線)
│   └── View.php             # View 基類(含模板引擎)
├── Controller/              # 業務控制器
│   └── UserController.php
├── Model/                   # 業務模型
│   └── UserModel.php
├── View/                    # 模板檔案
│   └── user/
│       ├── list.php
│       └── detail.php
├── Config/
│   └── database.php
└── public/
    └── index.php            # 單一入口

核心基類代碼

<?php
// Core/Application.php
class Application {
    public function run(): void {
        // 1. 解析路由
        $route = $this->parseRoute();
        // 2. 實例化 Controller
        $controllerClass = "App\\Controller\\{$route['controller']}Controller";
        $controller = new $controllerClass();
        // 3. 呼叫 Action
        $action = $route['action'] . 'Action';
        $controller->$action($route['params']);
    }
    
    private function parseRoute(): array {
        $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $parts = array_filter(explode('/', trim($uri, '/')));
        return [
            'controller' => $parts[0] ?? 'Index',
            'action'     => $parts[1] ?? 'index',
            'params'     => array_slice($parts, 2),
        ];
    }
}

// Core/Controller.php
class Controller {
    protected function model(string $name): object {
        $class = "App\\Model\\{$name}Model";
        return new $class();
    }
    
    protected function view(string $template, array $data = []): void {
        extract($data);
        include __DIR__ . "/../../View/{$template}.php";
    }
    
    protected function json(array $data, int $code = 200): void {
        http_response_code($code);
        header('Content-Type: application/json');
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
        exit;
    }
}

// Core/Model.php
class Model {
    protected PDO $db;
    
    public function __construct() {
        $config = require __DIR__ . '/../Config/database.php';
        $this->db = new PDO(
            "mysql:host={$config['host']};dbname={$config['dbname']};charset=utf8mb4",
            $config['user'], $config['pass'],
            [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
        );
    }
}

// Core/View.php (若引入模板引擎如 Twig/Blade,替換此處)
class View {
    public static function render(string $template, array $data = []): string {
        extract($data);
        ob_start();
        include __DIR__ . "/../View/{$template}.php";
        return ob_get_clean();
    }
}

業務代碼範例

<?php
// Model/UserModel.php
class UserModel extends Model {
    public function getById(int $id): ?array {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$id]);
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }
    
    public function getList(int $page = 1, int $size = 20): array {
        $offset = ($page - 1) * $size;
        $stmt = $this->db->prepare('SELECT * FROM users LIMIT ? OFFSET ?');
        $stmt->bindValue(1, $size, PDO::PARAM_INT);
        $stmt->bindValue(2, $offset, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

// Controller/UserController.php
class UserController extends Controller {
    public function indexAction(array $params): void {
        $page = (int)($_GET['page'] ?? 1);
        $users = $this->model('User')->getList($page);
        $this->view('user/list', ['users' => $users, 'page' => $page]);
    }
    
    public function detailAction(array $params): void {
        $id = (int)($params[0] ?? 0);
        $user = $this->model('User')->getById($id);
        if (!$user) {
            $this->json(['error' => 'User not found'], 404);
            return;
        }
        $this->view('user/detail', ['user' => $user]);
    }
}

// View/user/list.php
<h1>用戶列表 (第  頁) </h1>
<ul>

    <li><a href="/user/detail/"></a></li>

</ul>

// View/user/detail.php
<h1></h1>
<p>Email: </p>
<p>註冊時間: </p>

入口檔案

<?php
// public/index.php
require_once __DIR__ . '/../vendor/autoload.php'; // 或手動 require Core 檔案

$app = new App\Core\Application();
$app->run();

請求生命週期圖解


HTTP Request
    │
    ▼
public/index.php (單一入口)
    │
    ▼
Application::run()
    │
    ├── parseRoute() → Controller/Action/Params
    │
    ▼
new UserController()
    │
    ├── model('User') → new UserModel() → PDO 查詢
    │
    ▼
view('user/list', $data)
    │
    ├── extract($data)
    │
    ▼
include View/user/list.php → HTML 輸出
    │
    ▼
HTTP Response

常見誤區與修正

誤區後果修正
Controller 寫 SQL業務邏輯分散、難測試、無法複用下沉至 Model/Service/Repository
View 直接查 DB模板耦合資料層、安全風險、效能不可控Controller 準備好所有資料再傳給 View
Model 返回 HTML/JSON模型職責不純、難以適配多端Model 只返回純資料(陣列/DTO/Entity)
God Controller(萬能控制器)單檔案數千行、耦合度極高拆分為多個 Controller,抽象 Service 層
忽略輸出逃逸XSS 漏洞模板引擎自動逃逸 / 手動 htmlspecialchars

演進方向:從自建到成熟框架

  1. 引入依賴注入容器:解決 `new Model()` 硬編碼,支援介面綁定、單例、工廠。
  2. 抽象 Service 層:Controller 只做 HTTP 協議轉換,業務邏輯在 Service(事務邊界、跨模型協調)。
  3. 引入 ORM/Repository:Eloquent/Doctrine/Cycle ORM,型別安全、關聯載入、遷移管理。
  4. 路由系統增強:RESTful、中介軟體、群組、模型綁定、API 版本控制。
  5. 模板引擎升級:Twig/Blade/Latte,沙箱、繼承、宏、串流、自動逃逸。
  6. 驗證/授權/異常處理集中化:FormRequest、Policy、Exception Handler。
  7. 測試基礎設施:PHPUnit/Pest、Factory、DatabaseTransactions、Mockery。

何時選自建、何時選框架?

  • 🎯 自建/微框架:教學、極簡 API、嵌入式、學習原理、特殊約束環境
  • 🏢 Laravel:全棧產品、快速交付、生態豐富、團隊標準化
  • 🏛️ Symfony:企業級、長期維護、高度客製化、元件複用
  • ⚡ Slim / Lumen / API Platform:微服務、純 API、效能敏感

MVC 不是框架專利,而是「關注點分離」的工程智慧。理解其本質,無論用何種工具,都能寫出清晰、可維護、可演進的代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved