PHP 分页原理分析,大家可以看看


Posted in PHP onDecember 21, 2009

1、前言

分页显示是一种非常常见的浏览和显示大量数据的方法,属于web编程中最常处理的事件之一。对于web编程的老手来说,编写这种代码实在是和呼吸一样自然,但是对于初学者来说,常常对这个问题摸不着头绪,因此特地撰写此文对这个问题进行详细的讲解,力求让看完这篇文章的朋友在看完以后对于分页显示的原理和实现方法有所了解。本文适合初学者阅读,所有示例代码均使用php编写。

2、原理

所谓分页显示,也就是将数据库中的结果集人为的分成一段一段的来显示,这里需要两个初始的参数:

每页多少条记录($PageSize)?
当前是第几页($CurrentPageID)?

现在只要再给我一个结果集,我就可以显示某段特定的结果出来。
至于其他的参数,比如:上一页($PreviousPageID)、下一页($NextPageID)、总页数($numPages)等等,都可以根据前边这几个东西得到。
以mysql数据库为例,如果要从表内截取某段内容,sql语句可以用:select * from table limit offset, rows。看看下面一组sql语句,尝试一下发现其中的规率。

前10条记录:select * from table limit 0,10
第11至20条记录:select * from table limit 10,10
第21至30条记录:select * from table limit 20,10
……

这一组sql语句其实就是当$PageSize=10的时候取表内每一页数据的sql语句,我们可以总结出这样一个模板:

select * from table limit ($CurrentPageID - 1) * $PageSize, $PageSize

拿这个模板代入对应的值和上边那一组sql语句对照一下看看是不是那么回事。搞定了最重要的如何获取数据的问题以后,剩下的就仅仅是传递参数,构造合适的sql语句然后使用php从数据库内获取数据并显示了。以下我将用具体代码加以说明。

3、简单代码
请详细阅读以下代码,自己调试运行一次,最好把它修改一次,加上自己的功能,比如搜索等等。

<?php 

// 建立数据库连接 

$link = mysql_connect("localhost", "mysql_user", "mysql_password") 

or die("Could not connect: " . mysql_error()); 

// 获取当前页数 

if( isset( 

$_GET['page']) ){ 

$page = intval( 

$_GET['page'] ); 

} 

else{ 

$page = 1; 

} 

// 每页数量 

$PageSize = 10; 

// 获取总数据量 

$sql = "select count(*) as amount from table"; 

$result = mysql_query($sql); 

$row = mysql_fetch_row($result); 

$amount = $row['amount']; 

// 记算总共有多少页 

if( $amount ){ 

if( $amount < $page_size ){ $page_count = 1; } //如果总数据量小于$PageSize,那么只有一页 

if( $amount % $page_size ){ //取总数据量除以每页数的余数 

$page_count = (int)($amount / $page_size) + 1; //如果有余数,则页数等于总数据量除以每页数的结果取整再加一 

}else{ 

$page_count = $amount / $page_size; //如果没有余数,则页数等于总数据量除以每页数的结果 

} 

} 

else{ 

$page_count = 0; 

} 
// 翻页链接 

$page_string = ''; 

if( $page == 1 ){ 

$page_string .= '第一页|上一页|'; 

} 

else{ 

$page_string .= '<a href="/?page=1>";第一页</a>|<a href="/?page='."($page-1).'>上一页</a>|'; 

} 

if( ($page == $page_count) || ($page_count == 0) ){ 

$page_string .= '下一页|尾页'; 

} 

else{ 

$page_string .= '<a href="/?page='."($page+1).'>下一页</a>|<a href="/?page='."$page_count.'>尾页</a>'; 

} 

// 获取数据,以二维数组格式返回结果 

if( $amount ){ 

$sql = "select * from table order by id desc limit ". ($page-1)*$page_size .", $page_size"; 

$result = mysql_query($sql); 

while ( $row = mysql_fetch_row($result) ){ 

$rowset[] = $row; 

} 

}else{ 

$rowset = array(); 

} 

// 没有包含显示结果的代码,那不在讨论范围,只要用foreach就可以很简单的用得到的二维数组来显示结果 

?>

4、OO风格代码
以下代码中的数据库连接是使用的pear db类进行处理

<?php 

// FileName: Pager.class.php 

// 分页类,这个类仅仅用于处理数据结构,不负责处理显示的工作 

Class Pager 

{ 

var $PageSize; //每页的数量 

var $CurrentPageID; //当前的页数 

var $NextPageID; //下一页 

var $PreviousPageID; //上一页 

var $numPages; //总页数 

var $numItems; //总记录数 

var $isFirstPage; //是否第一页 

var $isLastPage; //是否最后一页 

var $sql; //sql查询语句 
function Pager($option) 

{ 

global $db; 

$this->_setOptions($option); 

// 总条数 

if ( !isset($this->numItems) ) 

{ 

$res = $db->query($this->sql); 

$this->numItems = $res->numRows(); 

} 

// 总页数 

if ( $this->numItems > 0 ) 

{ 

if ( $this->numItems < $this->PageSize ){ $this->numPages = 1; } 

if ( $this->numItems % $this->PageSize ) 

{ 

$this->numPages= (int)($this->numItems / $this->PageSize) + 1; 

} 

else 

{ 

$this->numPages = $this->numItems / $this->PageSize; 

} 

} 

else 

{ 

$this->numPages = 0; 

} 

switch ( $this->CurrentPageID ) 

{ 

case $this->numPages == 1: 

$this->isFirstPage = true; 

$this->isLastPage = true; 

break; 

case 1: 

$this->isFirstPage = true; 

$this->isLastPage = false; 

break; 

case $this->numPages: 

$this->isFirstPage = false; 

$this->isLastPage = true; 

break; 

default: 

$this->isFirstPage = false; 

$this->isLastPage = false; 

} 

if ( $this->numPages > 1 ) 

{ 

if ( !$this->isLastPage ) { $this->NextPageID = $this->CurrentPageID + 1; } 

if ( !$this->isFirstPage ) { $this->PreviousPageID = $this->CurrentPageID - 1; } 

} 

return true; 

} 

/*** 

* 

* 返回结果集的数据库连接 

* 在结果集比较大的时候可以直接使用这个方法获得数据库连接,然后在类之外遍历,这样开销较小 

* 如果结果集不是很大,可以直接使用getPageData的方式获取二维数组格式的结果 

* getPageData方法也是调用本方法来获取结果的 

* 

***/ 

function getDataLink() 

{ 

if ( $this->numItems ) 

{ 

global $db; 

$PageID = $this->CurrentPageID; 

$from = ($PageID - 1)*$this->PageSize; 

$count = $this->PageSize; 

$link = $db->limitQuery($this->sql, $from, $count); //使用Pear DB::limitQuery方法保证数据库兼容性 

return $link; 

} 

else 

{ 

return false; 

} 

} 

/*** 

* 

* 以二维数组的格式返回结果集 

* 

***/ 

function getPageData() 

{ 

if ( $this->numItems ) 

{ 

if ( $res = $this->getDataLink() ) 

{ 

if ( $res->numRows() ) 

{ 

while ( $row = $res->fetchRow() ) 

{ 

$result[] = $row; 

} 

} 

else 

{ 

$result = array(); 

} 

return $result; 

} 

else 

{ 

return false; 

} 

} 

else 

{ 

return false; 

} 

} 

function _setOptions($option) 

{ 

$allow_options = array( 

'PageSize', 

'CurrentPageID', 

'sql', 

'numItems' 

); 

foreach ( $option as $key => $value ) 

{ 

if ( in_array($key, $allow_options) && ($value != null) ) 

{ 

$this->$key = $value; 

} 

} 

return true; 

} 

} 

?>

<?php 

// FileName: test_pager.php 

// 这是一段简单的示例代码,前边省略了使用pear db类建立数据库连接的代码 

require "Pager.class.php"; 

if ( isset( 

$_GET['page']) ) 

{ 

$page = (int) 

$_GET['page']; 

} 

else 

{ 

$page = 1; 

} 

$sql = "select * from table order by id"; 

$pager_option = array( 

"sql" => $sql, 

"PageSize" => 10, 

"CurrentPageID" => $page 

); 

if ( isset( 

$_GET['numItems']) ) 

{ 

$pager_option['numItems'] = (int) 

$_GET['numItems']; 

} 

$pager = @new Pager($pager_option); 

$data = $pager->getPageData(); 

if ( $pager->isFirstPage ) 

{ 

$turnover = "首页|上一页|"; 

} 

else 

{ 

$turnover = "<a href='?page=1&numItems=".$pager->numItems."'>首页</a>|<a href="/?page=".$pager->PreviousPageID."&numItems=".$pager->numItems."'>上一页</a>|"; 

} 

if ( $pager->isLastPage ) 

{ 

$turnover .= "下一页|尾页"; 

} 

else 

{ 

$turnover .= "<a href="/?page=".$pager->NextPageID."&numItems=".$pager->numItems."'>下一页</a>|<a href="/?page=".$pager->numPages."&numItems=".$pager->numItems."'>尾页</a>"; 

} 

?>

需要说明的地方有两个:

这个类仅仅处理数据,并不负责处理显示,因为我觉得将数据的处理和结果的显示都放到一个类里边实在是有些勉强。显示的时候情况和要求多变,不如自己根据类给出的结果处理,更好的方法是根据这个Pager类继承一个自己的子类来显示不同的分页,比如显示用户分页列表可以:

<?php 

Class MemberPager extends Pager 

{ 

function showMemberList() 

{ 

global $db; 
$data = $this->getPageData(); 

// 显示结果的代码 

// ...... 

} 

} 

/// 调用 

if ( isset( 

$_GET['page']) ) 

{ 

$page = (int) 

$_GET['page']; 

} 

else 

{ 

$page = 1; 

} 

$sql = "select * from members order by id"; 

$pager_option = array( 

"sql" => $sql, 

"PageSize" => 10, 

"CurrentPageID" => $page 

); 

if ( isset( 

$_GET['numItems']) ) 

{ 

$pager_option['numItems'] = (int) 

$_GET['numItems']; 

} 

$pager = @new MemberPager($pager_option); 

$pager->showMemberList(); 

?>

第二个需要说明的地方就是不同数据库的兼容性,在不同的数据库里截获一段结果的写法是不一样的。
mysql: select * from table limit offset, rows
pgsql: select * from table limit m offset n
......
所以要在类里边获取结果的时候需要使用pear db类的limitQuery方法。

ok,写完收功,希望花时间看完这些文字的你不觉得是浪费了时间。

PHP 相关文章推荐
玩转虚拟域名◎+ .
Oct 09 PHP
PHP 文件上传源码分析(RFC1867)
Oct 30 PHP
PHP 可阅读随机字符串代码
May 26 PHP
用Simple Excel导出xls实现方法
Dec 06 PHP
解析在PHP中使用全局变量的几种方法
Jun 24 PHP
php使用多个进程同时控制文件读写示例
Feb 28 PHP
PHP整合PayPal支付
Jun 11 PHP
PHP实现的方程求解示例分析
Nov 11 PHP
php+ajax简单实现全选删除的方法
Dec 06 PHP
[原创]PHP实现字节数Byte转换为KB、MB、GB、TB的方法
Aug 31 PHP
Laravel6.2中用于用户登录的新密码确认流程详解
Oct 16 PHP
php获取是星期几的的一些常用姿势
Dec 15 PHP
c#中的实现php中的preg_replace
Dec 21 #PHP
php 空格,换行,跳格使用说明
Dec 18 #PHP
PHP 抓取新浪读书频道的小说并生成txt电子书的代码
Dec 18 #PHP
PHP strtotime函数详解
Dec 18 #PHP
php 日期时间处理函数小结
Dec 18 #PHP
php 计算两个时间戳相隔的时间的函数(小时)
Dec 18 #PHP
php 来访国内外IP判断代码并实现页面跳转
Dec 18 #PHP
You might like
PHP伪静态写法附代码
2008/06/20 PHP
php入门学习知识点八 PHP中for循环基本应用之九九乘法口绝表
2011/07/14 PHP
PHP请求Socket接口测试实例
2016/08/12 PHP
php  单例模式详细介绍及实现源码
2016/11/05 PHP
通过源码解析Laravel的依赖注入
2018/01/22 PHP
javascript表单验证和Window详解
2014/12/11 Javascript
js实现照片墙功能实例
2015/02/05 Javascript
jQuery EasyUI学习教程之datagrid点击列表头排序
2016/07/09 Javascript
js实现常用排序算法
2016/08/09 Javascript
jQuery Ajax请求后台数据并在前台接收
2016/12/10 Javascript
BootStrap轮播HTML代码(推荐)
2016/12/10 Javascript
深入理解jquery中的each用法
2016/12/14 Javascript
JS和canvas实现俄罗斯方块
2017/03/14 Javascript
解决layui前端框架 form表单,table表等内置控件不显示的问题
2018/08/19 Javascript
对angularJs中$sce服务安全显示html文本的实例
2018/09/30 Javascript
详解ES6中的Map与Set集合
2019/03/22 Javascript
JS实现“全选”和&quot;全不选&quot;功能代码实例
2020/02/06 Javascript
使用 Vue-TCB 快速在 Vue 应用中接入云开发的方法
2020/02/10 Javascript
python处理json数据中的中文
2014/03/06 Python
纯Python开发的nosql数据库CodernityDB介绍和使用实例
2014/10/23 Python
python检测远程服务器tcp端口的方法
2015/03/14 Python
使用Python的Scrapy框架编写web爬虫的简单示例
2015/04/17 Python
python字典多键值及重复键值的使用方法(详解)
2016/10/31 Python
高质量Python代码编写的5个优化技巧
2017/11/16 Python
python实现数独游戏 java简单实现数独游戏
2018/03/30 Python
在tensorflow中实现去除不足一个batch的数据
2020/01/20 Python
python实现简单的井字棋游戏(gui界面)
2021/01/22 Python
荣耀俄罗斯官网:HONOR俄罗斯
2020/10/31 全球购物
大专毕业生自我鉴定
2013/11/21 职场文书
学生感冒英文请假条
2014/02/04 职场文书
经济管理毕业生求职信
2014/03/15 职场文书
小学校园文化建设汇报材料
2014/08/19 职场文书
标准离婚协议书范文下载
2014/11/30 职场文书
2014年创先争优工作总结
2014/12/11 职场文书
住房公积金贷款工资证明
2015/06/12 职场文书
JS前端可视化canvas动画原理及其推导实现
2022/08/05 Javascript