在PHP编程中,分页是经常要用到的功能。最近我们接手的网站也需要加入这个功能,于是去网络上搜寻了一下。网络上也有不少介绍,有相应的例子。看了几个之后,决定自己写。用了大概30分钟时间就调通了,下面和大家分享一下心得。
要写一个分页函数不是很难,根据分页导航来显示对应的子数据集也不是很复杂。但是其中还是有不少细节的问题需要解决。比如,要传递哪些参数,返回什么;如何避免全表选择;如何灵活的输出导航条等等。
先看我的函数原型:
function getPageNav($uri, $selectsql, $countsql, &$navbar, &$outres, $curpage, $param, $recperpage=10)
这个函数中我使用了八个参数。其中有两个引用参数是用来返回导航条和结果数据集的。还有一个是可选参数。所以,实际上,要传递进函数的参数应该是5个。
- $uri表示点击哪个URI会引发这样的分页操作。一般而言,就是要显示导航条和结果数据集的页面。
- $selectsql 是可以返回“全部”记录的SQL语句,而$countsql是统计前一个SQL返回的记录数的SQL语句。这两个语句必须严格保持WHERE子句(以及可 能的GROUP BY/HAVING)的一致,但是返回字段可以完全不一致。例如,第一个可以返回数据库中所有的字段;而第二个只返回一个count()。在我当前的函 数中,我是要求这个$countsql返回且只返回一个count() as count的字段。
- $curpage表示当前要显示哪一页。当然,我们应该判断这个页数是否越界,不过这个不是关键问题。
- $param用来与$uri配合,构造类似list.php?page=5这样形式的链接。其中,list.php由$uri决定,而page由$param决定。
- $recperpage就是简单的一个确定每个页面显示多少条记录的参数。
我使用引用参数返回导航条和结果数据集是基于这样的考虑:我更愿意将“当前页”这个对象理解为要显示的分页数据以及相对应的导航条(尽管外观可能没有变化,但是诸如“前一页”对应的页面是会变化了的)。
一般在开发这样的需要分页的页面时,我的习惯是先完成一个没有分页的页面,然后再考虑分页的插入。我相信在目前,没有分页功能,但是迟早会加入分页功能的页面的数量不算少。所以,我这个函数的开发就是要考虑到如何不破坏这些页面现有的布局和内在逻辑驱动。当然,如果从一开始就加入分页的功能,这个函数当然也没有问题。
将countsql和selectsql分开是因为我个人的习惯。以前在开发C/S程序时,总习惯不通过函数对返回的记录集操作而得到记录的个数。一来这样返回的数据不一定准确,另一来这样做往往回引起对返回记录集的全扫描。当然,在一个高度并发的环境下,有可能在执行countsql后而执行selectsql之前另一个用户已经插入了新的符合条件的数据,因此countsql得到的数量和selectsql实际返回的数量可能有差别。但是这个问题不会象我们想象中的那么严重——在你的应用中,并发度可能永远没有那么高。而且,即使真的有这样的问题,我们可以通过事务来解决。
在显示分页数据的页面中,我们可以这样来调用这个函数:
if(isset($_GET['page']))
$curpage=$_GET['page'];
else
$curpage=1;
$selectsql='select u.username, u.picname, u.country, u.lastlogin, up.balance, up.translation from tbl_user u, tbl_user_point up where u.username=up.username and u.lastlogin>=$date3daysago order by u.lastlogin desc, up.balance';
$countsql='select count(*) as count from tbl_user u, tbl_user_point up where u.username=up.username and u.lastlogin>=$date3daysago;'
$navbar=;$res=;getPageNav(userlist.php, $selectsql, $countsql, $navbar, $res, $curpage, page, 10);
然后在需要显示数据的地方,对$res进行常规的遍历,而在需要显示导航条的地方用echo $navbar即可。
源代码就不公开了,因为我相信任何一个有PHP经验的人都可以很轻易的根据这样的一个提示而完成编写。
本文的目的不在于提供代码,而在于提供一种编写分页函数的思路。
Leave a Reply