僅涉及文章列表讀取、分頁,不含發布/編輯功能。演示如何用接口約束、單例模式、依賴注入構建清晰的 MVC 結構。
<?php
// 數據操作接口
interface DataOperation {
public function select(array $info); // 返回文章數據
public function selectNum(array $info); // 返回總條數(分頁用)
}
// 數據源接口(單例入口)
interface DataSource {
public static function getInstance();
}
// 控制器接口
interface Controller {
public function push($key, $value); // 註冊視圖/模型
public function pop($key); // 移除註冊
public function execute($key); // 執行分發
}
// 視圖接口
interface View {
public function display(); // 渲染輸出
}
?>
<?php
class DataBaseSource implements DataSource {
private static $instance = null;
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new PDO(
'mysql:host=localhost;dbname=article;charset=utf8',
'root', '123456',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
}
return self::$instance;
}
}
?>
<?php
abstract class DataBaseOperation implements DataOperation {
protected $db = null;
public function __construct() {
$this->db = DataBaseSource::getInstance();
}
// 子類必須實現 select/selectNum
}
?>
<?php
class Tech extends DataBaseOperation {
public function select(array $info) {
$sql = "SELECT * FROM articles WHERE category='tech' ORDER BY id DESC LIMIT :offset,:limit";
$st = $this->db->prepare($sql);
$st->bindValue(':offset', $info['offset'], PDO::PARAM_INT);
$st->bindValue(':limit', $info['limit'], PDO::PARAM_INT);
$st->execute();
return $st->fetchAll(PDO::FETCH_ASSOC);
}
public function selectNum(array $info) {
$st = $this->db->query("SELECT COUNT(*) FROM articles WHERE category='tech'");
return $st->fetchColumn();
}
}
?>
<?php
class ViewController implements Controller {
private $registry = [];
public function push($key, $value) { $this->registry[$key] = $value; }
public function pop($key) { unset($this->registry[$key]); }
public function execute($key) {
if (!isset($this->registry[$key])) {
throw new Exception("Module '$key' not registered");
}
$viewClass = $this->registry[$key];
$view = new $viewClass(); // 實例化視圖
$view->display();
}
}
?>
<?php
abstract class ArticleView implements View {
protected $smarty;
public function __construct() {
$this->smarty = new Smarty();
// $this->smarty->template_dir = ...;
}
}
class TechArticleView extends ArticleView {
public function display() {
// 1. 從控制器或請求獲取參數
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
// 2. 調用模型(這裡簡化,實際應通過控制器注入)
$model = new Tech();
$articles = $model->select(['offset'=>($page-1)*10, 'limit'=>10]);
$total = $model->selectNum([]);
// 3. 分配模板變量
$this->smarty->assign('articles', $articles);
$this->smarty->assign('pagination', [
'total' => $total,
'per_page' => 10,
'current' => $page
]);
// 4. 輸出
$this->smarty->display('tech_list.tpl');
}
}
?>
<?php
try {
$ctrl = new ViewController();
$ctrl->push('tech', 'TechArticleView');
// 可持續註冊其他頻道:$ctrl->push('sports', 'SportsArticleView');
$mod = $_GET['mod'] ?? $_POST['mod'] ?? 'tech';
$ctrl->execute($mod);
} catch (Exception $e) {
// 統一異常處理:記錄日誌、顯示友好錯誤頁
error_log($e->getMessage());
include 'error_500.php';
}
?>
$this->db,無需重複注入。try-catch 保證錯誤不外露堆棧信息。