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

PHP 分頁類完整實作:智慧型頁碼範圍計算與靈活配置

     編輯:PHP 相關知識

分頁是 Web 應用最常見的 UI 元件,但「目前頁、總頁數、顯示頁碼數」三者組合出的邊界條件極多。本文提供一個健壯、可測試、支援多種顯示模式的 Paginator 類,並詳細說明核心演算法。

核心類別

class Paginator
{
    /** @var int 每頁筆數 */
    private $perPage;
    /** @var int 顯示頁碼數量(含目前頁) */
    private $linkCount;

    public function __construct(int $perPage = 15, int $linkCount = 10)
    {
        $this->perPage = max(1, $perPage);
        $this->linkCount = max(3, $linkCount | 1); // 確保奇數,利於左右對稱
    }

    /**
     * 產生分頁資訊陣列
     * @param int $currentPage  目前頁碼 (1-based)
     * @param int $totalItems   總資料筆數
     * @return array ['pages' => [...], 'current' => int, 'total' => int, 'perPage' => int]
     */
    public function getLinks(int $currentPage, int $totalItems): array
    {
        $totalPages = max(1, (int)ceil($totalItems / $this->perPage));
        $currentPage = max(1, min($currentPage, $totalPages));

        $half = (int)floor($this->linkCount / 2);
        $start = max(1, $currentPage - $half);
        $end = min($totalPages, $start + $this->linkCount - 1);

        // 當尾部不足時,向前修正 start
        if ($end - $start + 1 < $this->linkCount) {
            $start = max(1, $end - $this->linkCount + 1);
        }

        $pages = [];
        for ($i = $start; $i <= $end; $i++) {
            $pages[] = [
                'page' => $i,
                'current' => $i === $currentPage,
                'url' => $this->buildUrl($i),
            ];
        }

        return [
            'pages' => $pages,
            'current' => $currentPage,
            'total' => $totalPages,
            'perPage' => $this->perPage,
            'first' => 1,
            'last' => $totalPages,
            'prev' => $currentPage > 1 ? $currentPage - 1 : null,
            'next' => $currentPage < $totalPages ? $currentPage + 1 : null,
        ];
    }

    protected function buildUrl(int $page): string
    {
        // 實際專案可注入 UrlGenerator 或使用 $_GET 重建
        $params = $_GET;
        $params['page'] = $page;
        return '?' . http_build_query($params);
    }
}

使用範例

$paginator = new Paginator(perPage: 20, linkCount: 9);
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$total = 1234; // 從 DB 取得 COUNT(*)

$pagination = $paginator->getLinks($page, $total);

// 視圖渲染(Twig/Blade/原生 PHP)
foreach ($pagination['pages'] as $p) {
    $class = $p['current'] ? 'active' : '';
    echo "{$p['page']} ";
}

// 首頁/尾頁/上一頁/下一頁
if ($pagination['prev']) echo "« Prev ";
if ($pagination['next']) echo "Next »";

核心演算法解析

  1. 總頁數:ceil(totalItems / perPage),至少 1 頁。
  2. 目前頁修正:限制在 [1, totalPages] 區間。
  3. 理想起始頁:currentPage - floor(linkCount/2),置中顯示。
  4. 邊界修正:
    • 起始頁 < 1 → 設為 1
    • 結束頁 > totalPages → 設為 totalPages,並反向修正起始頁
  5. 輸出結構化陣列:包含頁碼、是否當前、URL、首尾頁、上下頁,前端零邏輯渲染。

進階擴充建議

需求實作方向
SEO 友善 URL(/page/3) 注入 UrlGeneratorInterface,buildUrl() 產生路徑型 URL
AJAX 無限捲動 新增 getApiLinks() 回傳 JSON,前端 fetch 附加 page 參數
游標分頁 新增 CursorPaginator 子類,使用 WHERE id > ? ORDER BY id LIMIT ?
快取總筆數 建構子注入 CacheItemPoolInterface,getLinks() 先讀快取

單元測試關鍵案例

// PHPUnit 風格
$p = new Paginator(10, 5);
$this->assertEquals([1,2,3,4,5], array_column($p->getLinks(1, 100)['pages'], 'page'));
$this->assertEquals([3,4,5,6,7], array_column($p->getLinks(5, 100)['pages'], 'page'));
$this->assertEquals([96,97,98,99,100], array_column($p->getLinks(100, 1000)['pages'], 'page'));
$this->assertEquals([1,2,3], array_column($p->getLinks(2, 25)['pages'], 'page')); // 總頁數 < linkCount

這個 Paginator 類已在多個高流量專案驗證,核心邏輯不足 50 行,零依賴、高內聚、易擴充,是分頁功能的最佳起點。

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