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

PHP 分頁功能完整實作:從邏輯原理到可複用程式碼

     編輯:PHP 綜合知識

分頁核心參數

  • $totalRows:總資料筆數
  • $pageSize:每頁顯示筆數
  • $currentPage:目前頁碼(從 $_GET 取得)
  • $totalPages:總頁數 = ceil($totalRows / $pageSize)
  • $offset:資料庫 OFFSET = ($currentPage - 1) * $pageSize

完整分頁類別實作

<?php
class Paginator {
    private int $totalRows;
    private int $pageSize;
    private int $currentPage;
    private int $totalPages;
    private string $urlPattern; // 如 '/list?page={page}'

    public function __construct(int $totalRows, int $pageSize = 20, string $urlPattern = '') {
        $this->totalRows = max(0, $totalRows);
        $this->pageSize = max(1, $pageSize);
        $this->totalPages = (int)ceil($this->totalRows / $this->pageSize);
        $this->currentPage = $this->normalizePage((int)($_GET['page'] ?? 1));
        $this->urlPattern = $urlPattern ?: $this->detectUrlPattern();
    }

    private function normalizePage(int $page): int {
        return max(1, min($page, $this->totalPages ?: 1));
    }

    private function detectUrlPattern(): string {
        $base = rtrim($_SERVER['SCRIPT_NAME'], '/');
        $query = $_GET;
        unset($query['page']);
        $qs = $query ? '?' . http_build_query($query) : '';
        return $base . $qs . ($query ? '&' : '?') . 'page={page}';
    }

    public function getOffset(): int {
        return ($this->currentPage - 1) * $this->pageSize;
    }

    public function getLimit(): string {
        return "LIMIT {$this->getOffset()}, {$this->pageSize}";
    }

    public function getPageRange(int $displayCount = 9): array {
        $half = (int)floor($displayCount / 2);
        $start = max(1, $this->currentPage - $half);
        $end = min($this->totalPages, $start + $displayCount - 1);
        $start = max(1, $end - $displayCount + 1);
        return range($start, $end);
    }

    public function render(): string {
        if ($this->totalPages <= 1) return '';

        $html = '<nav aria-label="Pagination"><ul class="pagination">';

        // 首頁、上一頁
        if ($this->currentPage > 1) {
            $html .= $this->link(1, '« 首頁');
            $html .= $this->link($this->currentPage - 1, '‹ 上一頁');
        }

        // 頁碼區間
        foreach ($this->getPageRange() as $page) {
            $html .= $page === $this->currentPage
                ? "<li class=\"active\"><span>{$page}</span></li>"
                : $this->link($page, (string)$page);
        }

        // 下一頁、尾頁
        if ($this->currentPage < $this->totalPages) {
            $html .= $this->link($this->currentPage + 1, '下一頁 ›');
            $html .= $this->link($this->totalPages, '尾頁 »');
        }

        $html .= '</ul></nav>';
        return $html;
    }

    private function link(int $page, string $text): string {
        $url = str_replace('{page}', $page, $this->urlPattern);
        return "<li><a href=\"{$url}\">{$text}</a></li>";
    }

    // 取得分頁資訊陣列,供 API 回傳
    public function toArray(): array {
        return [
            'current_page' => $this->currentPage,
            'per_page' => $this->pageSize,
            'total_pages' => $this->totalPages,
            'total_rows' => $this->totalRows,
            'offset' => $this->getOffset(),
        ];
    }
}

使用範例

<?php
// 1. 取得總筆數
$pdo = new PDO($dsn, $user, $pass);
$total = $pdo->query("SELECT COUNT(*) FROM articles WHERE status=1")->fetchColumn();

// 2. 實例化分頁器
$pager = new Paginator($total, 15);

// 3. 查詢當頁資料
$stmt = $pdo->prepare("SELECT * FROM articles WHERE status=1 ORDER BY id DESC " . $pager->getLimit());
$stmt->execute();
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 4. 輸出分頁導航
echo $pager->render();

// API 模式回傳 JSON
// echo json_encode(['data' => $articles, 'pagination' => $pager->toArray()]);

進階功能擴充

  • 自訂 URL 結構:支援 /page/3、?p=3 等任意格式
  • Ajax 分頁:render() 改輸出 data-page 屬性,前端 JS 接管點擊
  • SEO 優化:加入 rel="prev/next"、canonical 標籤
  • 游標分頁:大資料量時用 WHERE id > :last_id LIMIT 20 替代 OFFSET

常見坑點提醒

  1. 總筆數查詢未加索引:COUNT(*) 應有 WHERE 條件索引支援
  2. OFFSET 深分頁效能崩潰:百萬筆資料第 50000 頁會全表掃描,必須改用游標分頁
  3. 頁碼未驗證:惡意傳入 page=-999 或 page=999999 導致錯誤或資源浪費
  4. URL 參數遺失:分頁連結必須保留原本的搜尋、篩選參數
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved