1、查询方式的复习以及bindColumn()的介绍
<?php
namespace _0819;
//! 查询方式
//!fetch + while
//!fetchAll + foreach
//!bindValue:值绑定到变量上
//!bindParam:引用绑定到变量上
//!bindColumn:将字段绑定到变量上
//!字段和数据表都要加反引号
// 'SELECT `id`,`name`,`email` FROM `staff`';
use PDO;
$db = new PDO('mysql:dbname=phpedu','root','root');
$sql = <<< SQL
SELECT `id`,`name`,`sex`,`email`
FROM `staff`;
SQL;
//sql语句对象
$stmt = $db->prepare($sql);
//执行sql
$stmt->execute();
// while,foreach,list()进行结果数组的解构,解构到变量中;
//!要在预处理对象上调用bindColumn函数
$stmt->bindColumn('id',$id);
$stmt->bindColumn('name',$name);
$stmt->bindColumn('sex',$sex);
$stmt->bindColumn('email',$email);
// 用表格进行格式化打印
$table = <<< TABLE
<style>
table {
border-collapse: collapse;
width:90%;
min-width:360px;
margin:30px auto;
text-align:center;
}
table,th,td {
border:1px solid #000;
padding:5px;
}
table caption {
font-size:18px;
margin-bottom:10px;
}
table thead {
background:lightcyan;
}
table tbody tr:hover {
cursor:pointer;
background:#efefef;
}
</style>
<table>
<caption>员工信息表</caption>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
TABLE;
//!PDO::FETCH_BOUND指获取常量:可以省的,如果出问题,再加上试试
while ($stmt->fetch(PDO::FETCH_BOUND)){
//拼装html代码
// !heredoc与vue不同,多行字符串中只允许出现变量,不允许出现表达式
// 对$sex进行重写
$sex = $sex ? '男':'女';
$table .= <<<TR
<tr>
<td>$id</td>
<td>$name</td>
<td>$sex</td>
<td>$email</td>
</tr>
TR;
// printf('%d : %s, %d, (%s)<br>',$id,$name,$sex,$email);
}
$table .= '</tbody></table>';
echo $table;
?>
上述运行结果:
2、分页的基本原理
# 分页原理与实现
## 1.为什么分页
1.可以限制查询的结果数量,减轻网络压力
2.分页后每次请求数据量变小,用户体检更好
---
## 2. 分页SQL
``` sql
-- 单行注释
/* 多行注释 */
--全部
SELECT * FROM `staff`;
/*
特点:
1.从索引0开始显示,依此类推:0,1,2,3,4,...
2.索引与id不是一回事,例如id=20,索引可能是2
3.如果表中有100条记录,那么索引范围:(0-99)
4.输出所有记录,即全部数据显示在一页中,只有一页
5.当前记录的索引,也可以叫"偏移量",sql中用"OFFSET"表示
*/
SELECT * FROM `staff` LIMIT 5 OFFSET 0;
--简写
--LIMIT 13 OFFSET 0 === LIMIT 0,13
SELECT * FROM `staff` LIMIT 0,5;
--OFFSET 0:默认,可以不写
--那如果要分页显示,只要修改偏移量就可以了
--以下是分页演示
--每页显示10条,从第1页开始(偏移量从0开始)
-- 第1页:OFFSET=0
--计算-> offset = (1-1) * 10 = 0
SELECT * FROM `staff` LIMIT 0,10;
--正在显示第 0 - 9 行 (共 10 行, 查询花费 0.0002 秒。)
--下一页的偏移量:从10开始
-- 第2页:OFFSET=10
--计算-> offset = (2-1) * 10 = 10
SELECT * FROM `staff` LIMIT 10,10;
--正在显示第 10 - 19 行 (共 10 行, 查询花费 0.0002 秒。)
--下一页的偏移量:从20开始
-- 第2页:OFFSET=20
--计算-> offset = (3-1) * 10 = 20
SELECT * FROM `staff` LIMIT 20,10;
--正在显示第 20 - 29 行 (共 10 行, 查询花费 0.0002 秒。)
--下一页的偏移量:从30开始
/**
分析:
1.分页查询中,变化的是起始偏移量,不变的是每页的数量
2.数量,当前页数,和当前偏移量之间是有一定的关系的
3.根据数量和页数,可以计算出偏移量
4.公式 : 偏移量 = (页数-1) * 数量
*/
```
## 3.获取当前分页数据的条件
1.当前页码: `$_GET['p']`
2.当前页显示数量:`$num`
3.当前页起始偏移量:`OFFSET = (当前页码 - 1) * 显示数量`
4.SQL模板: `SELECT * FROM table_name LIMIT offset,num`
---
## 4.显示分页条需要的条件
1.总记录数:`SELECT COUNT(*) FROM table_name`;
2.总页数:`ceil(总记录数 / 每页显示数)`,结果要向上取整,确保完整性
<!-- 总页数是计算出来的,在当前的sql语句中是拿不到的 -->
---
## 5.结论
### 5.1 `三个数据是已知的`
1.当前页码
2.显示数量
3.总记录数量
### 5.2 `2个需要计算的`
1.每页起始偏移量
2.总页数
3、获取分页条
<?php
// * 获取分页条
namespace _0819;
use PDO;
//连接
$db = new PDO('mysql:dbname=phpedu','root','root');
//1.页数
//! ??指默认值
$page = $_GET['p'] ?? 1;
echo '当前页数 : p = '. $page . '<br>';
//2.数量
$num = 5;
echo '当前数量 : num = ' . $num . '<br>';
//3.偏移量 = (页数 - 1) * 数量
$offset = ($page - 1) * $num;
echo '当前偏移量 : offset = ' . $offset . '<br>';
// 4.计算总记录数
// SELECT CEIL(COUNT(*)/5) AS 'total' FROM `staff`;
// SELECT COUNT(*) AS 'total' FROM `staff`;
$sql = 'SELECT COUNT(*) AS `total` FROM `staff`';
$stmt = $db->prepare($sql);
$stmt->execute();
//将总数量绑定到一个变量上
$stmt->bindColumn('total',$total);
$stmt->fetch();
echo '当前总记录数量: total = ' . $total . '<br>';
//向上取整计算总页数
$pages = ceil($total/$num);
echo '当前总页数: pages = ' . $pages . '<br>';
$sql = <<< SQL
SELECT *
FROM `staff`
LIMIT $offset,$num;
SQL;
$stmt = $db->prepare($sql);
$stmt->execute();
$staffs = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo '<hr>';
if(count($staffs) === 0){
echo '查询结果为空';
}else{
foreach($staffs as $staff) {
//!extract()函数 将一个关联数组直接解析到一个变量列表中
extract($staff);//$id,$name,$sex,$email
printf('%d-%s-%s-%s<br>',$id,$name,$sex,$email);
}
}
echo '<hr>';
?>
上述运行结果:
4、分页展示数据
<?php
require 'demo3.php';
require '/page_refer.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分页展示数据</title>
<style>
table {
border-collapse: collapse;
/* width: 90%; */
min-width: 200px;
margin: 30px 0;
text-align: center;
}
table,
th,
td {
border: 1px solid #000;
padding: 5px;
}
table thead {
background-color: lightcyan;
}
table caption {
font-size: larger;
margin-bottom: 8px;
}
body>p {
display: flex;
}
p>a {
text-decoration: none;
color: #555;
border: 1px solid;
padding: 5px 10px;
margin: 10px 2px;
}
.active {
background-color: seagreen;
color: white;
border: 1px solid seagreen;
}
</style>
</head>
<body>
<table>
<caption>员工信息表</caption>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<?php foreach ($staffs as $staff) : extract($staff) ?>
<tr>
<td><?= $id ?></td>
<td><?= $name ?></td>
<td><?= $sex ?></td>
<td><?= $email ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<p>
<?php for ($i = 1; $i <= $pages; $i++) : ?>
<?php
//页码跳转的url
$url = $_SERVER['PHP_SELF'] . '?p=' . $i;
//实现页码高亮
$page = $_GET['p'] ?? 1;
$active = ($i == $page) ? 'active':null;
?>
<a href="<?=$url?>" class="<?=$active?>"><?= $i ?></a>
<?php endfor ?>
</p>
</body>
</html>
上述运行结果:
5、简洁的分页展示
<?php
require 'demo3.php';
require 'page_refer.php';
//实现页码高亮
$page = $_GET['page'] ?? 1;
$pageChange = createPages((int)$page, ceil((int)$total / 5));
function upp($a){
next($a);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="demo4.css">
<title>分页展示数据</title>
<style>
table {
border-collapse: collapse;
/* width: 90%; */
min-width: 200px;
margin: 30px 0;
text-align: center;
}
table,
th,
td {
border: 1px solid #000;
padding: 5px;
}
table thead {
background-color: lightcyan;
}
table caption {
font-size: larger;
margin-bottom: 8px;
}
body>p {
display: flex;
}
p>a {
text-decoration: none;
color: #555;
border: 1px solid;
padding: 5px 10px;
margin: 10px 2px;
}
.active {
background-color: seagreen;
color: white;
border: 1px solid seagreen;
}
</style>
</head>
<body>
<table>
<caption>员工信息表</caption>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<?php foreach ($staffs as $staff) : extract($staff) ?>
<tr>
<td><?= $id ?></td>
<td><?= $name ?></td>
<td><?= $sex ?></td>
<td><?= $email ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<p>
<?php for ($i = 1; $i <= $pages; $i++) : ?>
<?php
//页码跳转的url
//$_SERVER['PHP_SELF']代表当前自己的php脚本
$url = $_SERVER['PHP_SELF'] . '?page=' . $i;
$active = ($i == $page) ? 'active' : null;
?>
<a href="<?= $url ?>" class="<?= $active ?>"><?= $i ?></a>
<?php endfor ?>
</p>
<p class="midPage">
<?php $a = $_GET['page']-1;?>
<?php if($a>0) :?>
<?php $url2 = $_SERVER['PHP_SELF'] . '?page=' . $a;?>
<a href="<?= $url2 ?>" class="upPage" onclick="upp($a)">上一页</a>
<?php endif?>
<?php foreach ($pageChange as $v) : ?>
<?php if (isset($v)) : ?>
<a href="<?php echo $_SERVER['PHP_SELF'] . '?page=' . $v ?>"
<?php echo $page == $v ? 'class="active"' : null ?>
>
<?= $v ?>
</a>
<?php else : ?>
<a>......</a>
<?php endif ?>
<?php endforeach ?>
<?php $b = $_GET['page']+1;?>
<?php if($b<$pages) :?>
<?php $url3 = $_SERVER['PHP_SELF'] . '?page=' . $b;?>
<a href="<?= $url3 ?>" class="upPage">下一页</a>
<?php endif?>
</p>
</body>
</html>
上述运行结果:
6、简洁的且好看的分页展示
page_refer.php
<?php
// ! 仿php.cn分页作用参考代码
/**
* 生成分页码
*
* @param integer $page 当前页
* @param integer $pages 总页数
* @return array
*/
function createPages(int $page, int $pages): array
{
// 当前是第8页, 共计20页
// [1, ... 6, 7, 8, 9, 10, .... 20]
// 当前是第10页, 共计20页
// [1, ... 8, 9, 10, 11, 12, .... 20]
// 1. 生成与总页数长度相同的递增的整数数组
$pageArr = range(1, $pages);
// 2. 只需要当前和前后二页, 其它页码用 false/null 来标记
$paginate = array_map(function ($p) use ($page, $pages) {
if($page==4){
return ($p ==1 ||$p == $pages || abs($page-$p) <=3) ? $p : null;
}elseif($page==3){
return ($p ==1 ||$p == $pages || abs($page-$p) <=4) ? $p : null;
}elseif($page==2){
return ($p ==1 ||$p == $pages || abs($page-$p) <=5) ? $p : null;
}elseif($page==1){
return ($p ==1 ||$p == $pages || abs($page-$p) <=6) ? $p : null;
}else{
return ($p ==1 ||$p == $pages || abs($page-$p) <=2) ? $p : null;
}
}, $pageArr);
// dump($paginate);
// 去重, 替换
$before = array_unique(array_slice($paginate, 0, $page));
$after = array_unique(array_slice($paginate, $page));
// 用解构进行合并
return [...$before, ...$after];
}
demo3.php
<?php
// * 获取分页条
namespace _0819;
use PDO;
//连接
$db = new PDO('mysql:dbname=phpedu','root','root');
//1.页数
//! ??指默认值
$page = $_GET['page'] ?? 1;
echo '当前页数 : p = '. $page . '<br>';
//2.数量
$num = 5;
echo '当前数量 : num = ' . $num . '<br>';
//3.偏移量 = (页数 - 1) * 数量
$offset = ($page - 1) * $num;
echo '当前偏移量 : offset = ' . $offset . '<br>';
// 4.计算总记录数
// SELECT CEIL(COUNT(*)/5) AS 'total' FROM `staff`;
// SELECT COUNT(*) AS 'total' FROM `staff`;
$sql = 'SELECT COUNT(*) AS `total` FROM `staff`';
$stmt = $db->prepare($sql);
$stmt->execute();
//将总数量绑定到一个变量上
$stmt->bindColumn('total',$total);
$stmt->fetch();
echo '当前总记录数量: total = ' . $total . '<br>';
//向上取整计算总页数
$pages = ceil($total/$num);
echo '当前总页数: pages = ' . $pages . '<br>';
$sql = <<< SQL
SELECT *
FROM `staff`
LIMIT $offset,$num;
SQL;
$stmt = $db->prepare($sql);
$stmt->execute();
$staffs = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo '<hr>';
if(count($staffs) === 0){
echo '查询结果为空';
}else{
foreach($staffs as $staff) {
//!extract()函数 将一个关联数组直接解析到一个变量列表中
extract($staff);//$id,$name,$sex,$email
printf('%d-%s-%s-%s<br>',$id,$name,$sex,$email);
}
}
echo '<hr>';
?>
demo4.php
<?php
require 'demo3.php';
require 'page_refer.php';
//实现页码高亮
$page = $_GET['page'] ?? 1;
$pageChange = createPages((int)$page, ceil((int)$total / 5));
function upp($a){
next($a);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="demo4.css">
<title>分页展示数据</title>
<style>
table {
border-collapse: collapse;
/* width: 90%; */
min-width: 200px;
margin: 30px 0;
text-align: center;
}
table,
th,
td {
border: 1px solid #000;
padding: 5px;
}
table thead {
background-color: lightcyan;
}
table caption {
font-size: larger;
margin-bottom: 8px;
}
body>p {
display: flex;
}
p>a {
text-decoration: none;
color: #555;
border: 1px solid;
padding: 5px 10px;
margin: 10px 2px;
}
.active {
background-color: seagreen;
color: white;
border: 1px solid seagreen;
}
</style>
</head>
<body>
<table>
<caption>员工信息表</caption>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<?php foreach ($staffs as $staff) : extract($staff) ?>
<tr>
<td><?= $id ?></td>
<td><?= $name ?></td>
<td><?= $sex ?></td>
<td><?= $email ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<p>
<?php for ($i = 1; $i <= $pages; $i++) : ?>
<?php
//页码跳转的url
//$_SERVER['PHP_SELF']代表当前自己的php脚本
$url = $_SERVER['PHP_SELF'] . '?page=' . $i;
$active = ($i == $page) ? 'active' : null;
?>
<a href="<?= $url ?>" class="<?= $active ?>"><?= $i ?></a>
<?php endfor ?>
</p>
<p class="midPage">
<?php $a = $_GET['page']-1;?>
<?php if($a>0) :?>
<?php $url2 = $_SERVER['PHP_SELF'] . '?page=' . $a;?>
<a href="<?= $url2 ?>">上一页</a>
<?php endif?>
<?php foreach ($pageChange as $v) : ?>
<?php if (isset($v)) : ?>
<a href="<?php echo $_SERVER['PHP_SELF'] . '?page=' . $v ?>"
<?php echo $page == $v ? 'class="active"' : null ?>
>
<?= $v ?>
</a>
<?php else : ?>
<a>......</a>
<?php endif ?>
<?php endforeach ?>
<?php $b = $_GET['page']+1;?>
<?php if($b<= $pages) :?>
<?php $url3 = $_SERVER['PHP_SELF'] . '?page=' . $b;?>
<a href="<?= $url3 ?>">下一页</a>
<?php endif?>
</p>
</body>
</html>
上述运行结果: