批改状态:合格
老师批语:php中文网不教授没有用武之地的课程, 设计程序要从用户体验出发, 便民利民才能走的更远, 参考支付宝,微信给你带来的遍历~(除了微信中聊天转账功能不分离有待商榷)
数据分页其实就是SQL构造语句的Limit使用,其有两种形式:SELECT * FROM user LIMIT 0,10;和SELECT * FROM USER LIMIT 10 OFFSET 0;。若是LIMIT 0,10则偏移量是0,10是记录条数,而是使用LIMIT 10 OFFSET 0表示意思是一样的,即若LIMIT后面只有一个数字,则表示取得记录条数。
关于偏移量的计算是offset=(page-1)*num;。page是当前页的页码,即是index.php?p=2中2。num则表示每页要显示的记录条数。
写本博文开始自己封装常用的类了,如数据库类Db,目前是第一版,实现了数据库链式查询和CURD操作,至于预处理和事务则后续版本中逐渐增加。
declare(strict_types=1);namespace WOXIAOYAO;use \PDO;use \Exception;/** @Descripttion: 自己封装的PDO类,可支持MySQL、MSSQL、ORACLE和SQLite的数据库操作* @version: 1.0.0* 准备要完成功能:1、支持PDO的query和exec(1.0.0) 2、支持PDO的预处理 3、支持PDO的事务处理*/// 准备知识:四种数据库连接方式// MySQL:'dsn'=>'mysql:host=localhost;dbname=talk','username'=>'root','password'=>'123456'// MSSQL:'dsn'=>'odbc:Driver={SQL Server};Server=192.168.1.60;Database=his','username'=>'sa','password'=>'xxxxx'// Oracle:'dsn'=>'oci:dbname=orcl','username'=>'BAOCRM','password'=>'BAOCRM'// SQLite:'dsn'=>'sqlite:'.dirname(__FILE__).'\log.db'// 抽象类完成单例模式连接、准备处理方法和接口的定义// 抽象类的保护静态成员为所有子类共享abstract class aDb{// 定义单例模式连接protected static $pdo = null;protected static $config = null;final protected function connect(array $config){$config = array_change_key_case($config, CASE_LOWER);if ($config === false) throw new Exception('连接配置不是数组');if (empty($this->is_assoc($config))) throw new Exception('连接配置不是关联数组');if (empty(self::$config)) {self::$config = $config;} else if (!empty(array_diff_assoc(self::$config, $config))) {self::$config = $config;} else {return self::$pdo;}try {$pdo = new \PDO(self::$config['dsn'], self::$config['username'], self::$config['password']);// 若没报错则先清除旧连接,重置为新连接self::$pdo = null;self::$pdo = $pdo;self::$pdo->query("set names utf8");//属性名 属性值 数组以关联数组返回self::$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);} catch (\Exception $e) {echo '数据库连接失败,详情: ' . $e->getMessage() . ' 请在配置文件中数据库连接信息';exit();}}// 判断是否是关联数组final protected function is_assoc(array $arr){if (is_array($arr)) {$key = array_keys($arr);return $key === array_keys($key) ? false : true;}return null;}// 定义接口规范// 链式规范abstract public function table(string $table);abstract public function field(string $fields);abstract public function where($where);abstract public function order(string $order);abstract public function limit(string $limit);// 单条记录和多条记录查询abstract public function find();abstract public function select();// 插入、更新和删除规范abstract public function insert(array $data);abstract public function update(array $data);abstract public function delete();}// 工作类,实现CURD操作class Db extends aDb{private $res;private $table;private $fields = '*';private $where = 'true';private $order;private $limit;function __construct(array $config){$this->connect($config);}function getConfig(){return parent::$config;}function getPDO(){return parent::$pdo;}private function reset(){// $table='';$this->fields = '*';$this->where = 'true';$this->order = '';$this->limit = '';}// 链式查询function table(string $table){if (!is_string($table)) throw new Exception("参数是字符串,形式如'user'表示user表");if (!empty($table))$this->table = $table;return $this;}function field(string $fields){if (!is_string($fields)) throw new Exception("参数是字符串,形式如'id,name,pwd'表示获取3个字段");if (!empty($fields))$this->fields = $fields;return $this;}function where($where){if (is_string($where)) {if (!empty($fields))$this->where .= " and {$where}";return $this;}if ($this->is_assoc($where)) {while (current($where)) {$this->where .= ' and ' . key($where) . '=' . current($where);next($where);}return $this;}throw new Exception('请检查条件');}function order(string $order){if (!is_string($order)) throw new Exception("参数是字符串,形式如'id asc'表示id升序");if (!empty($order))$this->order = $order;return $this;}function limit(string $limit){if (!is_string($limit)) throw new Exception("参数是字符串,形式如'0,5'表示偏移0数量是5");if (!empty($limit))$this->limit = $limit;return $this;}// 查询单条记录function find(){try {if (empty($this->table)) throw new Exception('没有查询表');$sql = "SELECT {$this->fields} FROM {$this->table} WHERE {$this->where}";if (!empty($this->order))$sql .= " ORDER BY {$this->order}";$this->res = parent::$pdo->query($sql);$this->reset();return $this->res->fetch(PDO::FETCH_ASSOC);} catch (\PDOException $e) {return '查询错误信息:' . $e->getMessage();}}// 查询所有记录function select(){try {if (empty($this->table)) throw new Exception('没有查询表');$sql = "SELECT {$this->fields} FROM {$this->table} WHERE {$this->where}";if (!empty($this->order))$sql .= " ORDER BY {$this->order}";if (!empty($this->limit))$sql .= " LIMIT {$this->limit}";$this->res = parent::$pdo->query($sql);$this->reset();return $this->res->fetchAll(PDO::FETCH_ASSOC);} catch (\PDOException $e) {return '查询错误信息:' . $e->getMessage();}}// 插入、更新和删除操作public function insert(array $data){if (empty($this->is_assoc($data))) throw new Exception('插入数据不是关联数组');if (empty($this->table)) throw new Exception('插入时必须指定表');$sql = "INSERT INTO {$this->table}";$key = key($data);$value = "'" . current($data) . "'";next($data);while (current($data)) {$key .= "," . key($data);$value .= ",'" . current($data) . "'";next($data);}$sql .= " ({$key}) VALUES ({$value})";$this->res = parent::$pdo->exec($sql);$this->reset();return $this->res;}public function update(array $data){if (empty($this->is_assoc($data))) throw new Exception('更新数据不是关联数组');if (empty($this->table)) throw new Exception('更新时必须指定表');if ($this->where == 'true') throw new Exception('更新时必须指定条件');$sql = "UPDATE {$this->table}";$item = key($data) . "='" . current($data) . "'";next($data);while (current($data)) {$item .= "," . key($data) . "='" . current($data) . "'";next($data);}$sql .= " SET {$item} WHERE {$this->where}";$this->res = parent::$pdo->exec($sql);$this->reset();return $this->res;}public function delete(){try {if (empty($this->table)) throw new Exception('删除时必须指定表');if ($this->where == 'true') throw new Exception('删除时必须指定条件');$sql = "DELETE FROM {$this->table} WHERE {$this->where}";$this->res = parent::$pdo->exec($sql);$this->reset();return $this->res;} catch (\PDOException $e) {return '查询错误信息:' . $e->getMessage();}}}
上面已经准备了数据库,也理解了分页的知识,下面代码反而比较简单,直接看代码
//pagnate.phprequire_once 'Db.php';use WOXIAOYAO\Db;$config = ['dsn' => 'mysql:host=localhost;dbname=test','username' => 'root','password' => 'root'];$obj = new Db($config);//分页获取数据$num = 10;$res = $obj->table('user')->field('count(id) as total')->select();$total = intval($res[0]['total']);$pages = ceil($total / $num);$page = $_GET['p'] ?? 1;$offset = ($page - 1) * $num;$users = $obj->table('user')->limit("{$offset},{$num}")->select();
// index.php<style>* {margin: 0;padding: 0;box-sizing: border-box;}a {text-decoration: none;display: inline-block;/* width: 2em; */height: 2em;line-height: 2em;}.container {width: 60vw;margin: 1em auto;}td {text-align: center;}.page {margin-top: 1em;text-align: center;}td a:first-child {margin-right: 5px;}td a:last-child {margin-left: 5px;}.page a {padding: 0 0.5em;margin: 0 5px;}.page a.cur {background-color: #007d20;color: white;}</style><div class="container"><table border='1' cellspacing="0" width="100%"><caption>用户信息表</caption><thead><tr bgColor="lightgray"><th>ID</th><th>name</th><th>password</th><th>操作</th></tr></thead><tbody><?phpinclude_once 'pagnate.php';foreach ($users as $user) {$trdata = "<tr>";foreach ($user as $item) {$trdata .= "<td>{$item}</td>";}$trdata .= "<td><a href='#'>编辑</a><a href='#'>删除</a></td>";$trdata .= "</tr>";echo $trdata;}?></tbody></table><div class="page"><?phpecho "<a href='{$_SERVER["PHP_SELF"]}?p=1'>首页</a>";$prev = ($page - 1 > 1) ? ($page - 1) : 1;if ($page > 1)echo "<a href='{$_SERVER["PHP_SELF"]}?p={$prev}'>上一页</a>";for ($i = 1; $i <= $pages; $i++) :if ($i == $page)echo "<a class='cur' href='{$_SERVER["PHP_SELF"]}?p={$i}'>{$i}</a>";elseecho "<a href='{$_SERVER["PHP_SELF"]}?p={$i}'>{$i}</a>";endfor;$next = ($page + 1) < $pages ? ($page + 1) : $pages;if ($page < $pages)echo "<a href='{$_SERVER["PHP_SELF"]}?p={$next}'>下一页</a>";echo "<a href='{$_SERVER["PHP_SELF"]}?p={$pages}'>未页</a>";?></div></div>
无论是PHP中文网或老师演示的省略号仅仅展示,而无实际功能,而我认为前省略号相当于前一页,后面省略号相当于后一页。具体代码我在老师的基础上进行了精简。下面分布导航既有老师所演示的省略号功能,而且省略号也能起到跳转页码作用。
//pagnate.php// 改进的导航栏(在基础版中增加)$startPage = 1;// 显示页码数最好为奇数$showPage = 5;if (($page - ceil(($showPage - 1) / 2)) > $startPage)$startPage = $page - ceil(($showPage - 1) / 2);
//index2.php// 分页数据代码不变,对分页页码导航代码重新编写<div class="page"><?phpecho "<a href='{$_SERVER["PHP_SELF"]}?p=1'>首页</a>";$prev = ($page - 1 > 1) ? ($page - 1) : 1;if ($startPage > 1)echo "<a href='{$_SERVER["PHP_SELF"]}?p={$prev}'>...</a>";for ($i = $startPage; $i < $startPage+$showPage; $i++) :if ($i == $page)echo "<a class='cur' href='{$_SERVER["PHP_SELF"]}?p={$i}'>{$i}</a>";elseecho "<a href='{$_SERVER["PHP_SELF"]}?p={$i}'>{$i}</a>";endfor;$next = ($page + 1) < $pages ? ($page + 1) : $pages;if ($startPage+$showPage <= $pages+1)echo "<a href='{$_SERVER["PHP_SELF"]}?p={$next}'>...</a>";echo "<a href='{$_SERVER["PHP_SELF"]}?p={$pages}'>未页</a>";?></div>

关于单条数据的编辑和删除: 其实就是数据库的更新和删除操作,比较简单,我这里就不演示了
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号