Correcting teacher:天蓬老师
Correction status:qualified
Teacher's comments:看来你对变量过滤器很感兴趣, 这是一个好习惯, 希望保持下去
player
数据表
初始数据(部分)
connect.php
<?php
try {
// PDO对象
$pdo = new PDO('mysql:host=localhost;dbname=phpedu;port=3306;charset=utf8', 'root', 'root');
} catch (Exception $e) {
printf('链接异常, 异常信息: %s', $e->getMessage());
die;
}
pagination.php
<?php
class Pagination
{
// 第一页
private $start = 1;
// 一页可容纳的记录数
private $pageSize = 3;
// 显示的页码个数
private $pageNumSize = 5;
// 显示的页码列表
private $pageNumList = [];
// 总页数
private $pageCount = 0;
// 页码左右偏移量
private $pageNumOffset = 0;
// 当前页码
private $currentPage = 1;
// 记录总数
private $rowCount = 0;
public function __construct(int $rowCount, int $currentPage = 1, int $pageSize = 3, int $pageNumSize = 5)
{
// 初始化各种属性
$this->rowCount = $rowCount;
$this->pageSize = $pageSize;
$this->pageNumSize = $pageNumSize;
$this->pageNumOffset = ($pageNumSize - 1) / 2;
$this->pageCount = ceil(floatval($rowCount) / $pageSize);
/* 当传入的当前页码效于最小页码时,初始化为1;大于最大页码时,初始化为最大页码 */
$this->currentPage = $currentPage < 1 ? 1 : ($currentPage > $this->pageCount ? $this->pageCount : $currentPage);
$this->getPageNumList();
}
/**
* 获取要显示的页码列表
*/
private function getPageNumList()
{
// 如果要显示的页码数量>=总页码数量,则显示所有页码。
if ($this->pageCount <= $this->pageNumSize) {
$this->pageNumList = range(1, $this->pageCount, 1);
return;
}
// 起始页码,取“当前页码-页码偏移量”和起始页码的最大值。
$pageNumStart = ($this->currentPage - $this->pageNumOffset) < $this->start ? $this->start : ($this->currentPage - $this->pageNumOffset);
// 结束页码,取“当前页码+页码偏移量”和总页码数的最小值。
$pageNumEnd = ($pageNumStart + $this->pageNumSize - 1) > $this->pageCount ? $this->pageCount : ($pageNumStart + $this->pageNumSize - 1);
// 若结束页码等于总页码,则再计算一次起始页码(避免当前页到结束页码的差值小于页码偏移量的情况)
if ($pageNumEnd === $this->pageCount) {
// 起始页码,取“最大页码-要显示的页码数量+1”和起始页码的最大值。
$pageNumStart = ($this->pageCount - $this->pageNumSize + 1) < $this->start ? $this->start : ($this->pageCount - $this->pageNumSize + 1);
}
// 生成要显示的页码数组
$this->pageNumList = range($pageNumStart, $pageNumEnd, 1);
}
// 拼接字符串,形成分页HTML代码字符串。
public function getPagination()
{
$pageHtml = '<div class="pagination">';
// 首页
$tmpHtml = $this->currentPage === 1 ? '<span class="pageNum disabled">首页</span>'
: sprintf('<a class="pageNum" href="%s?p=1&r=%d">首页</a>', $_SERVER['PHP_SELF'], $this->pageSize);
$pageHtml .= $tmpHtml;
// 上一页
$tmpHtml = $this->currentPage === 1 ? '<span class="pageNum disabled">上一页</span>'
: sprintf('<a class="pageNum" href="%s?p=%d&r=%d">上一页</a>', $_SERVER['PHP_SELF'], $this->currentPage - 1, $this->pageSize);
$pageHtml .= $tmpHtml;
// 间隔符
$tmpHtml = $this->pageNumList[0] >= 2 ? '...' : '';
$pageHtml .= $tmpHtml;
// 页码
foreach ($this->pageNumList as $pageNum) {
$tmpHtml = $pageNum == $this->currentPage ? sprintf('<span class="active">%d</span>', $pageNum)
: sprintf('<a class="pageNum {$pageNum}" href="%s?p=%d&r=%d">%d</a>', $_SERVER['PHP_SELF'], $pageNum, $this->pageSize, $pageNum);
$pageHtml .= $tmpHtml;
}
// 间隔符
$tmpHtml = $this->pageNumList[array_key_last($this->pageNumList)] + 1 <= $this->pageCount ? '...' : '';
$pageHtml .= $tmpHtml;
// 下一页
$tmpHtml = $this->currentPage >= $this->pageCount ? '<span class="pageNum disabled">下一页</span>'
: sprintf('<a class="pageNum" href="%s?p=%d&r=%d">下一页</a>', $_SERVER['PHP_SELF'], $this->currentPage + 1, $this->pageSize);
$pageHtml .= $tmpHtml;
// 末页
$tmpHtml = $this->currentPage >= $this->pageCount ? '<span class="pageNum disabled">末页</span>'
: sprintf('<a class="pageNum" href="%s?p=%d&r=%d">末页</a>', $_SERVER['PHP_SELF'], $this->pageCount, $this->pageSize);
$pageHtml .= $tmpHtml;
// 总页码
$pageHtml .= "<span>共{$this->pageCount}页</span>";
// 页码跳转表单
$tmpHtml = "<form action='{$_SERVER['PHP_SELF']}' method='get'> <input type='text' name='p'><input type='hidden' name='r' value='{$this->pageSize}'><button type='submit'>跳转</button></form>";
$pageHtml .= $tmpHtml;
$pageHtml .= '</div>';
return $pageHtml;
}
// 直接向浏览器输出分页信息
public function echoPagination()
{
echo $this->getPagination();
}
}
player.php
<?php
require('../out.php');
require('connect.php');
// 查询记录总数
$sql = 'SELECT count(`id`) as row_count FROM `player`';
$count = ($pdo->query($sql)->fetch(PDO::FETCH_NUM))[0] ?? 0;
// 单页球员数量
$rowPerPage = ($_GET['r'] && !empty($_GET['r'])) ? $_GET['r'] : 3;
$rowPerPage = filter_var($rowPerPage, FILTER_VALIDATE_INT) ? $rowPerPage : 3;
// 当前页
$currentPage = ($_GET['p'] && !empty($_GET['p'])) ? $_GET['p'] : 1;
$currentPage = filter_var($currentPage, FILTER_VALIDATE_INT, ['option' => []]) ? $currentPage : 1;
$currentPage = $currentPage < 1 ? 1 : ($currentPage > ceil(floatval($count) / $rowPerPage) ? ceil(floatval($count) / $rowPerPage) : $currentPage);
// 查询页面数据
$start = ($currentPage - 1) * $rowPerPage;
$sql = "SELECT * FROM `player` LIMIT {$start}, {$rowPerPage}";
$players = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
// 加载显示列表数据的模板
require('player_list.php');
player_list.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>球员列表</title>
<style>
@import 'style/page_style.css';
@import 'style/page_style.css';
@import 'style/list.css';
</style>
</head>
<?php
require('pagination.php');
?>
<body>
<table cellspacing="0" align="center">
<caption>球员列表</caption>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>球队</th>
<th>身高(cm)</th>
<th>体重(kg)</th>
<th>位置</th>
<th>创建时间</th>
<th>修改时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if (!empty($players) && count($players) > 0) : ?>
<?php foreach ($players as $player) : ?>
<tr>
<td><?php echo $player['id']; ?></td>
<td><?php echo $player['name']; ?></td>
<td><?php echo $player['team']; ?></td>
<td><?php echo $player['height']; ?></td>
<td><?php echo $player['weight']; ?></td>
<td><?php echo $player['position']; ?></td>
<td><?php echo date('Y-m-d H:i:s', $player['create_time']); ?></td>
<td><?php echo date('Y-m-d H:i:s', $player['update_time']); ?></td>
<td>
<a href="edit_player.php?id=<?php echo $player['id']; ?>&pos=<?php echo urlencode($_SERVER['QUERY_STRING']); ?>">修改</a>
<a href="del_player.php?id=<?php echo $player['id']; ?>&name=<?php echo $player['name']; ?>&pos=<?php echo urlencode($_SERVER['QUERY_STRING']); ?>">删除</a>
</td>
</tr>
<?php endforeach; ?>
<?php else : ?>
<tr>
<td colspan="9">啥也没查到...</td>
</tr>
<?php endif ?>
</tbody>
</table>
<?php (new Pagination($count, $currentPage, $rowPerPage, 5))->echoPagination();
?>
<?php //echo (new Pagination($count, $currentPage, 3, 5));
?>
</body>
</html>
do_update.php
<?php
require_once('connect.php');
require_once('../out.php');
$sql = "UPDATE `player` SET `name` = :name, `team` = :team, `height` = :height, `weight` = :weight, `position` = :position, `update_time` = :update_time WHERE `id` = :id";
$param = $_POST;
$param['update_time'] = time();
$pos = $param['pos'];
unset($param['pos']);
$stmt = $pdo->prepare($sql);
$stmt->execute($param);
if ($stmt->rowCount() === 1) {
if (empty($pos))
echo ("<script>alert('修改成功');window.history.back();</script>");
else {
$pos = urldecode($pos);
echo ("<script>alert('修改成功');window.location='/0512/player.php?{$pos}';</script>");
}
} else {
echo ("<script>alert('修改失败');</script>");
}
edit_player.php
<?php
require 'connect.php';
require('../out.php');
$id = $_GET['id'];
if (empty($id) || !filter_var($id, FILTER_VALIDATE_INT, ['options' => ['min-range' => 1]])) {
echo ("<script>alert('无效的ID值!');window.history.go(-1);</script>");
die;
}
$sql = "SELECT * FROM `player` WHERE `id` = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id]);
if ($stmt->rowCount() !== 1) {
echo ("<script>alert('无效的ID值');window.history.go(-1);</script>");
die;
}
$player = $stmt->fetch(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>修改球员信息</title>
<style>
@import url('style/common.css');
@import url('style/edit.css');
</style>
</head>
<body>
<section>
<div class="player-edit-header">修改球员信息</div>
<div class="player-info">
<form action="do_update.php" method="post">
<input type="hidden" name="id" value="<?php echo $player['id']; ?>">
<input type="hidden" name="pos" value="<?php echo $_GET['pos']; ?>">
<div class="info-item">
<label for="name">姓名: </label>
<input type="text" name="name" id="name" value="<?php echo $player['name']; ?>" required autofocus>
</div>
<div class="info-item">
<label for="team">球队: </label>
<input type="text" name="team" id="team" value="<?php echo $player['team']; ?>" required>
</div>
<div class="info-item">
<label for="height">身高(cm): </label>
<input type="number" name="height" id="height" value="<?php echo $player['height']; ?>" required>
</div>
<div class="info-item">
<label for="weight">体重(kg): </label>
<input type="number" name="weight" id="weight" value="<?php echo $player['weight']; ?>" required>
</div>
<div class="info-item">
<label for="position">位置: </label>
<input type="text" name="position" id="position" value="<?php echo $player['position']; ?>" required>
</div>
<div class="info-item">
<button type="submit">保存</button>
</div>
</div>
</form>
</section>
</body>
</html>
do_del.php
<?php
require_once('../out.php');
// 球员id
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
// 球员列表的分页参数
$pos = !empty($_GET['pos']) ? '?' . urldecode($_GET['pos']) : '';
// 无效的id,不处理
if(!$id) {
echobr("<script>alert('无效的参数');window.location.href='/0512/player.php{$pos}'</script>");
}
require('connect.php');
$sql = "DELETE FROM `player` WHERE `id` = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $id]);
// 判断处理条数
if ($stmt->rowCount() === 1) {
echobr("<script>alert('删除成功');window.location.href='/0512/player.php{$pos}'</script>");
} else {
echobr("更新失败");
printfpre($stmt->errorInfo());
echobr("<a href='/0512/player.php{$pos}'>返回</a>");
}
?>
del_player.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>确认删除</title>
<style>
@import url('style/common.css');
@import url('style/del.css');
</style>
</head>
<body>
<section>
<span>确认要删除<strong><?php echo $_GET['name'] ?></strong>吗?</span>
<a href="/0512/player.php<?php echo $_GET['pos'] ? '?' . $_GET['pos'] : ''; ?>" class="btn">取 消</a>
<a href="do_del.php?id=<?php echo $_GET['id'] ?>&pos=<?php echo urlencode($_GET['pos']) ?>">确 认</a>
</section>
</body>
</html>
运行效果:
PlayerOpera1.php
<?php
namespace di\operate;
use PDO;
// 基于构造方法的注入方式
class PlayerOpera1 {
// PDO实例
private $pdo = null;
public function __construct($pdo)
{
$this->pdo = $pdo;
}
/**
* 查询所有球员信息
*/
public function allPlayers() {
return $this->pdo->query("SELECT * FROM `player`")->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 查询某个球员
*/
public function player($id) {
if(filter_var($id, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]))
return $this->pdo->query("SELECT * FROM `player` WHERE `id` = {$id}")->fetch(PDO::FETCH_ASSOC);
else {
echo('无效的参数');die;
}
}
}
PlayerOpera2.php
<?php
namespace di\operate;
// 基于方法参数的注入方式
use PDO;
class PlayerOpera2 {
public function __construct()
{
}
/**
* 查询所有球员信息
*/
public function allPlayers(PDO $pdo) {
return $pdo->query("SELECT * FROM `player`")->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 查询某个球员
*/
public function player(int $id, PDO $pdo) {
if(filter_var($id, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]))
return $pdo->query("SELECT * FROM `player` WHERE `id` = {$id}")->fetch(PDO::FETCH_ASSOC);
else {
echo ('无效的参数');die;
}
}
}
client.php
<?php
namespace di;
require('../out.php');
require('PlayerOpera1.php');
require('PlayerOpera2.php');
use di\operate\PlayerOpera1;
use di\operate\PlayerOpera2;
// 客户端
require('../0512/connect.php');
// 1. 基于构造方法的注入方式
$playerOpera1 = new PlayerOpera1($pdo);
// 查询出所有球员数据
$players = $playerOpera1->allPlayers();
// printfpre($players);
/* result:
Array
(
[0] => Array
(
[id] => 1
[name] => 勒布朗-詹姆斯
[team] => 湖人
[height] => 203
[weight] => 113
[position] => F-G
[create_time] => 1589387682
[update_time] => 1589477867
)
[1] => Array
(
[id] => 2
[name] => 安东尼-戴维斯
[team] => 湖人
[height] => 208
[weight] => 115
[position] => F-C
[create_time] => 1589387682
[update_time] => 1589387682
)
略...
*/
// 2. 基于方法参数的注入方式
$playerOpera2 = new PlayerOpera2;
// 查询某个球员的信息
$id = 1;
$player = $playerOpera2->player($id, $pdo);
printfpre($player);
/* result:
Array
(
[id] => 1
[name] => 勒布朗-詹姆斯
[team] => 湖人
[height] => 203
[weight] => 113
[position] => F-G
[create_time] => 1589387682
[update_time] => 1589477867
)
*/
分页的实现, 封装成了一个分页类, 可以在其他地方使用, 慢慢体会到封装类带来的代码复用的遍历.
两种注入方式: 当只需要对类中的某个方法中注入外部对象时, 使用基于方法参数的注入即可. 若类中的多个方法都需要注入某个相同的外部对象, 使用基于方法参数的注入方式, 会使得代码冗余. 此时, 使用基于构造方法的注入方式, 把外部对象通过构造方法注入并设定为类的一个属性值, 这样在用到该外部对象的时候, 直接使用指向该外部对象的类属性即可.