分頁是 Web 應用中處理大量數據展示的基礎技術。本文將系統梳理 PHP 分頁的核心原理、傳統實現方式,並對比現代框架中的最佳實踐,幫助開發者構建高效、可維護的分頁組件。
早期 PHP 開發中(如 PHP 4/5 時代),分頁通常遵循以下流程:
<?php
// 1. 獲取並驗證當前頁碼
$currentPage = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
// 2. 配置參數
$pageSize = 10;
// 3. 連接數據庫(建議使用 PDO 或 MySQLi)
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'user', 'pass');
// 4. 獲取總記錄數
$stmt = $pdo->query('SELECT COUNT(*) FROM articles');
$totalRows = $stmt->fetchColumn();
$totalPages = ceil($totalRows / $pageSize);
// 5. 修正頁碼範圍
$currentPage = min($currentPage, max(1, $totalPages));
// 6. 查詢當前頁數據
$offset = ($currentPage - 1) * $pageSize;
$stmt = $pdo->prepare('SELECT id, title, author, created_at FROM articles ORDER BY id DESC LIMIT :offset, :limit');
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->bindValue(':limit', $pageSize, PDO::PARAM_INT);
$stmt->execute();
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!-- 7. 顯示數據表格 -->
<table class="table">
<thead>
<tr><th>ID</th><th>標題</th><th>作者</th><th>發布時間</th></tr>
</thead>
<tbody>
<?php foreach ($articles as $row): ?>
<tr>
<td><?= htmlspecialchars($row['id']) ?></td>
<td><?= htmlspecialchars($row['title']) ?></td>
<td><?= htmlspecialchars($row['author']) ?></td>
<td><?= htmlspecialchars($row['created_at']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- 8. 渲染分頁導航 -->
<nav aria-label="分頁導航">
<ul class="pagination">
<?php if ($currentPage > 1): ?>
<li><a href="?page=1">首頁</a></li>
<li><a href="?page=<?= $currentPage - 1 ?>">上一頁</a></li>
<?php endif; ?>
<?php
// 顯示頁碼範圍(如當前頁前後各 2 頁)
$start = max(1, $currentPage - 2);
$end = min($totalPages, $currentPage + 2);
for ($i = $start; $i <= $end; $i++): ?>
<li class="<?= $i === $currentPage ? 'active' : '' ?>">
<a href="?page=<?= $i ?>"><?= $i ?></a>
</li>
<?php endfor; ?>
<?php if ($currentPage < $totalPages): ?>
<li><a href="?page=<?= $currentPage + 1 ?>">下一頁</a></li>
<li><a href="?page=<?= $totalPages ?>">尾頁</a></li>
<?php endif; ?>
</ul>
</nav>
生產環境建議使用經過驗證的庫,而非手寫邏輯:
RESTful API 推薦採用標準化回應格式:
{
"data": [...],
"meta": {
"current_page": 3,
"per_page": 15,
"total": 342,
"last_page": 23,
"links": {
"first": "/api/articles?page=1",
"prev": "/api/articles?page=2",
"next": "/api/articles?page=4",
"last": "/api/articles?page=23"
}
}
}
| 問題 | 後果 | 解決方案 |
|---|---|---|
| 直接使用 `$_GET['page']` 未驗證 | SQL 注入、邏輯錯誤、負載異常 | 強制轉型 `intval()`,限制最小值 1,最大值 `$totalPages` |
| 每頁筆數過大或可由用戶控制 | 記憶體耗盡、響應超時 | 固定合理值(10-50),或提供有限選項(10, 20, 50) |
| 總數查詢與列表查詢未在事務中保持一致 | 並發下總頁數與實際數據不符 | 讀已提交隔離級通常可接受;極高一致性需求可用鎖或快照 |
| 分頁導航生成過多鏈接(如萬頁) | 頁面體積過大、SEO 稀釋 | 僅顯示當前頁附近頁碼、首尾頁、省略號 |
分頁看似簡單,實則涉及數據庫優化、用戶體驗、架構規範等多維考量。初學者應先掌握基礎邏輯與手寫實現,理解 `LIMIT/OFFSET` 原理;進階開發者則應熟悉框架內建組件、大數據優化策略、API 設計規範,並根據業務場景選擇傳統分頁、游標分頁或無限滾動。記住:沒有銀彈,只有適合當前業務規模與增長預期的方案。