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

打造可重用的 PHP 分頁函數:從零開始的完整實作

     編輯:PHP 綜合知識

為何需要獨立的分頁函數?

列表頁幾乎是每個專案的標配,但分頁邏輯(總筆數、每頁筆數、當前頁碼、URL 參數保持、導航列渲染)若分散在各控制器中,不僅重複造輪子,維護時更得改十幾個檔案。將分頁封裝為獨立函數 pageft(),放入 pageft.php,隨時 include 即用,才是專業開發的基本功。

函數設計目標

  • 零侵入:不直接輸出 HTML,僅產生供呼叫端使用的全域變數
  • 高可攜:不綁定特定資料庫、框架或 URL 結構
  • 彈性樣式:提供原始資料,前端自行決定用 <ul>、<nav> 或 Bootstrap 元件渲染

核心變數輸出說明

變數型別用途
$firstcountintSQL LIMIT 起始位移(($page-1)*$pagesize)
$displaypgint當前頁碼(已修正邊界)
$pagenavarray導航列資料結構,含首頁、上一頁、頁碼陣列、下一頁、尾頁、總頁數等鍵值

實作範例:pageft.php

<?php
/**
 * 通用分頁函數
 * @param int $total_rows  總筆數
 * @param int $pagesize    每頁筆數,預設 20
 * @param int $pagenum     導航列顯示頁碼數,預設 10
 * @param string $url_base 基礎 URL(含 ? 之前部分),預設自動偵測
 */
function pageft($total_rows, $pagesize = 20, $pagenum = 10, $url_base = '') {
    global $firstcount, $displaypg, $pagenav;

    // 1. 計算總頁數
    $total_pages = ceil($total_rows / $pagesize);
    if ($total_pages < 1) $total_pages = 1;

    // 2. 取得當前頁碼(支援 $_GET['page'] 或 $_GET['p'])
    $page = isset($_GET['page']) ? (int)$_GET['page'] : (isset($_GET['p']) ? (int)$_GET['p'] : 1);
    if ($page < 1) $page = 1;
    if ($page > $total_pages) $page = $total_pages;

    // 3. 產生 LIMIT 位移
    $firstcount = ($page - 1) * $pagesize;
    $displaypg = $page;

    // 4. 建構基礎 URL(保留除 page 外的所有查詢參數)
    if ($url_base === '') {
        $url_base = $_SERVER['PHP_SELF'] . '?' . http_build_query(array_diff_key($_GET, ['page' => '', 'p' => '']));
        if ($url_base !== '') $url_base .= '&';
    }

    // 5. 產生導航陣列
    $nav = [
        'first'   => 1,
        'prev'    => max(1, $page - 1),
        'next'    => min($total_pages, $page + 1),
        'last'    => $total_pages,
        'current' => $page,
        'total'   => $total_pages,
        'pages'   => [],
        'url_base' => $url_base,
    ];

    // 頁碼範圍計算(以當前頁為中心,前後各 $pagenum/2)
    $half = (int)($pagenum / 2);
    $start = max(1, $page - $half);
    $end   = min($total_pages, $start + $pagenum - 1);
    if ($end - $start + 1 < $pagenum) {
        $start = max(1, $end - $pagenum + 1);
    }
    for ($i = $start; $i <= $end; $i++) {
        $nav['pages'][] = $i;
    }

    $pagenav = $nav;
}
?>

呼叫端使用範例(list.php)

<?php
require_once 'db.php';          // 您的資料庫連線
require_once 'pageft.php';      // 載入分頁函數

// 1. 取得總筆數
$total = $pdo->query("SELECT COUNT(*) FROM articles WHERE status=1")->fetchColumn();

// 2. 呼叫分頁函數(每頁 15 筆,導航列顯示 10 個頁碼)
pageft($total, 15, 10);

// 3. 取得資料(使用 $firstcount 做 LIMIT)
$stmt = $pdo->prepare("SELECT id, title, created_at FROM articles WHERE status=1 ORDER BY id DESC LIMIT ?, 15");
$stmt->execute([$firstcount]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

<!DOCTYPE html>
<html>
<head><title>文章列表</title></head>
<body>
<table>
    <thead><tr><th>ID</th><th>標題</th><th>日期</th></tr></thead>
    <tbody>
    <?php foreach ($rows as $r): ?>
        <tr><td><?=$r['id']?></td><td><?=htmlspecialchars($r['title'])?></td><td><?=$r['created_at']?></td></tr>
    <?php endforeach; ?>
    </tbody>
</table>

<!-- 導航列渲染 -->
<nav aria-label="Pagination">
    <ul class="pagination">
        <?php
        $n = $pagenav;
        // 首頁 / 上一頁
        echo '<li><a href="' . $n['url_base'] . 'page=1">首頁</a></li>';
        echo '<li><a href="' . $n['url_base'] . 'page=' . $n['prev'] . '">上一頁</a></li>';

        // 頁碼
        foreach ($n['pages'] as $p) {
            $cls = ($p == $n['current']) ? ' class="active"' : '';
            echo '<li' . $cls . '><a href="' . $n['url_base'] . 'page=' . $p . '">' . $p . '</a></li>';
        }

        // 下一頁 / 尾頁
        echo '<li><a href="' . $n['url_base'] . 'page=' . $n['next'] . '">下一頁</a></li>';
        echo '<li><a href="' . $n['url_base'] . 'page=' . $n['last'] . '">尾頁</a></li>';
        ?>
    </ul>
</nav>
<p>共 <?=$pagenav['total']?> 頁 / <?=$total?> 筆資料</p>
</body>
</html>

進階擴充建議

  • 類別化重構:將函數改為 Pager 類別,支援多實例、鏈式呼叫($pager->setTotal($total)->setPageSize(15)->render())。
  • 支援 AJAX 無限捲動:新增 getApiResponse() 回傳 JSON 結構,前端以 fetch 串接。
  • URL 重寫友善:允許傳入 url_pattern = '/article/page/{page}',配合 Nginx/Apache Rewrite 產生美觀網址。
  • 快取總筆數:對高流量列表,將 COUNT(*) 結果寫入 Redis 緩存 30-60 秒,大幅降低 DB 壓力。

結語

一個優良的分頁函數,核心在於「只做運算、不做輸出」。將分頁邏輯與呈現層徹底分離,才能在 MVC、API、SSR、CSR 等各種架構下複用。將 pageft.php 放入專案共用函式庫,下次建列表頁時,只需三行代碼即可完成專業級分頁——這才是「一勞永逸」的正確姿勢。

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