- 熟悉PDO所有常用方法,并实例演示
- 数据库配置
// 连接参数
return [
// 类型
'type' => $type ?? 'mysql',
// 默认主机名
'host' => $username ?? 'localhost',
// 默认编码集
'charset' => $charset ?? 'utf8',
// 默认端口号
'port' => $porst ?? '3306',
// 默认用户名
'username' => $usernam ?? 'root',
// 默认用户的密码
'password' => $password ?? 'root',
// 默认数据库
'dbname' => $dbname ?? 'phpedu',
];
- 连接数据库
// 1. 导入配置参数
//__DIR__获取当前目录的路径
$config = require __DIR__ . '\\0829-1config.php';
// print_r($config);
extract($config);
// new PDO(数据源, 用户名, 密码);
// $dsn = '数据库类型:host=主机名;dbname=默认数据库;charset=默认编码集;port=默认端口';
// $dsn = 'mysql:host=localhost;dbname=phpedu;charset=utf8;port=3306';
try {
//要执行的代码,$dsn代表数据源
$dsn = sprintf('%s:host=%s;dbname=%s',$type,$host,$dbname);
$pdo =new PDO($dsn, $username, $password);
// var_dump($pdo);
} catch (PDOException $e) {
die($e->getMessage());
}
新增数据
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
// ?占位符;:name命名占位符
$sql = 'INSERT `user` SET `name`=?, `email`=?, `password`=?;';//将?分别替换成:name,:email,:password;占位符前面的:可以不加
// sql语句对象(预处理对象)
$stmt = $pdo->prepare($sql);
// var_dump($stmt);
// 将占位符与变量名绑定
//1)bindParam()参数绑定
// bindParam(): 参数与指定的变量名进行绑定,也叫引用传参
//常量:PDO::PARAM_STR表示 SQL 中的 CHAR、VARCHAR 或其他字符串类型
$stmt->bindParam(1, $name, PDO::PARAM_STR, 30);//$stmt->bindParam(':name', $name, PDO::PARAM_STR, 30);
$stmt->bindParam(2, $email,PDO::PARAM_STR, 100);//$stmt->bindParam(':email', $email, PDO::PARAM_STR, 100);
$stmt->bindParam(3, $password, PDO::PARAM_STR, 40);//$stmt->bindParam(':password', $password, PDO::PARAM_STR, 40);
//变量名与值进行绑定
$name = '张龙';
$email = 'zhanglong@qq.com';
$password = sha1('156793');
//执行
$stmt->execute();
//简易方法:可以省略参数绑定的步骤,直接在execute()传参时进行绑定,但此时参数必须放在一个数组中
// 如:?匿名占位符可写成$stmt->execute(['张龙2','zhanglong2@qq.com',sha1('1562793')]);
// 如:使用命名占位符, 则需传一个关联数组,键名就是占位符,可写成$res=$stmt->execute(['name'=>'张龙2', 'email'=>'zhanglong2@qq.com','password'=> sha1('1562793')]);
//2)bindValue()值绑定
// $name='张士';
// $email='zhangshi@qq.com';
// $password=sha1('589802');
// $stmt->bindValue(1,$name,PDO::PARAM_STR);
// $stmt->bindValue(2,$email,PDO::PARAM_STR);
// $stmt->bindValue(3,$password,PDO::PARAM_STR);
// $stmt->execute();
//rowCount():返回操作成功后受影响的记录数量,这里是指新增的记录数量
echo '成功新增'.$stmt->rowCount().'条记录';
// 3、关闭
// $pdo = null;
unset($pdo);
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
// ?占位符;:name命名占位符
$sql = 'INSERT `user` SET `name`=:name, `email`=:email, `password`=:password;';
// sql语句对象(预处理对象)
$stmt = $pdo->prepare($sql);
$res=$stmt->execute(['name'=>'张龙2', 'email'=>'zhanglong2@qq.com','password'=> sha1('1562793')]);
echo '成功新增'.$stmt->rowCount().'条记录';
// 3、关闭
// $pdo = null;
unset($pdo);
- 更新数据
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
// 更新数据时一定要有条件
$sql = 'UPDATE `user` SET `name`=?, `email`=?, `password`=? WHERE `id` = ?;';
// sql语句对象(预处理对象)
$stmt = $pdo->prepare($sql);
$res=$stmt->execute(['赵虎', 'zhaohu@qq.com',sha1('580293'),9]);
//rowCount():返回操作成功后受影响的记录数量,这里是指新增的记录数量
echo $stmt->rowCount() === 1 ? '成功更新了 ' . $stmt->rowCount() . ' 条记录' : '没有记录被更新';
// 3、关闭
unset($pdo);
- 删除数据
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
// 更新数据时一定要有条件
$sql = 'DELETE FROM `user` WHERE `id` = ?;';
// sql语句对象(预处理对象)
$stmt = $pdo->prepare($sql);
$res=$stmt->execute([8]);
//rowCount():返回操作成功后受影响的记录数量,这里是指新增的记录数量
echo $stmt->rowCount() === 1 ? '成功删除了 ' . $stmt->rowCount() . ' 条记录' : '没有记录被删除';
// 3、关闭
unset($pdo);
- 查询数据
- fetch()+while()
// pdo查询数据:fetch()+while()逐条遍历
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
// 更新数据时一定要有条件
$sql = 'SELECT `id`,`name`,`email` FROM `user` WHERE `id` > ?;';
// sql语句对象(预处理对象)
$stmt = $pdo->prepare($sql);
//给查询结果增加一个条件:符合时逐条遍历显示结果,否则打印错误信息
if($stmt->execute([5])){
// 逐条遍历,fetch()返回一维数组,将数据表的记录指针自动下移
// $a = $stmt->fetch();
// printf('<pre>%s</pre>',print_r($a,true));
//数据查询完之后再进行遍历,则不会显示数据,可用while循环遍历操作
while($a=$stmt->fetch()){
printf('<pre>%s</pre>',print_r($a,true));
}
}else{
// 返回一个错误信息的数组
printf('<pre>%s</pre>',print_r($stmt->errorInfo(),true));
// 调试方法:打印出执行的SQL预处理语句,进行检查
$stmt->debugDumpParams();
}
// 3、关闭
unset($pdo);
- fetchALl() + foreach()
// pdo查询数据:fetchALl() + foreach()
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
// 更新数据时一定要有条件
$sql = 'SELECT `id`,`name`,`email` FROM `user` WHERE `id` < ?;';
// sql语句对象(预处理对象)
$stmt = $pdo->prepare($sql);
//给查询结果增加一个条件:符合时显示结果,否则打印错误信息
if($stmt->execute([5])){
// 一次性获取所有满足条件的数据信息
$a = $stmt->fetchAll();
//数据查询完以二维数组显示,可用foreach操作
foreach($a as $value){
vprintf('<li>id = %d, name = %s, email = %s</li>', $value);
}
}else{
// 返回一个错误信息的数组
printf('<pre>%s</pre>',print_r($stmt->errorInfo(),true));
// 调试方法:打印出执行的SQL预处理语句,进行检查
$stmt->debugDumpParams();
}
// 3、关闭
unset($pdo);
- 将每个字段绑定到变量上
// pdo查询数据:将每个字段绑定到变量上
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
// 查询数据时一定要有条件
$sql = 'SELECT `id`,`name`,`email` FROM `user` WHERE `id` < ?;';
// sql语句对象(预处理对象)
$stmt = $pdo->prepare($sql);
$stmt->execute([5]);
// 将三个字段与三个变量进行绑定,通过列名进行绑定
$stmt->bindColumn('id', $id);
$stmt->bindColumn('name', $name);
$stmt->bindColumn('email', $email);
while ($user = $stmt->fetch()) {
printf('<pre>%s</pre>',print_r($user,true));
}
// 3、关闭
unset($pdo);
- 查询符合条件的记录数量
//查询符合条件的记录数量
// 1、连接数据库
$config = require __DIR__ . '\\0829-2.php';
//2、操作
//获取满足条件的记录数量不能用$stmt->rowCount(),要用COUNT(*)
// COUNT(*):字段名,并不直观,所以给个别名
$sql = 'SELECT COUNT(*) AS `count` FROM `user` WHERE `id` < ?;';
// 预处理语句
$stmt = $pdo->prepare($sql);
$stmt->execute([5]);
//将别名count绑定到变量
$stmt->bindColumn('count', $count);
$stmt->fetch(PDO::FETCH_BOUND);
echo '满足条件记录数量是: ', $count, ' 条记录';
// 3. 关闭
$pdo = null;
- fetch()+while()
- trait 常用场景
- 代码复用
//1、实现代码复用,图片单继承限制
trait Demo{
public function getUser(){
return '姓名:'.$this->name.',年龄:'.$this->age.'岁';
}
}
trait Demos{
public function getUsers(){
//get_class_vars() 函数返回由类的默认属性组成的数组;参数为类名
//self可以访问本类中的静态属性和静态方法,可以访问父类中的静态属性和静态方法。用self时可以不用实例化
//__CLASS__:当前类的名称;等价于self::class
return sprintf('<pre>%s</pre>', print_r(get_class_vars(self::class), true));
}
}
class Demo1{
//插入多个trait,用,隔开
use Demo,Demos;//相当于把Demo和Demos的方法都复制到了本类中
protected $name='张三';
protected $age='30';
}
class Demo2{
use Demo;
protected $name='李四';
protected $age='40';
}
echo (new Demo1)->getUser().'<br>';
echo (new Demo1)->getUsers().'<br>';
echo (new Demo2)->getUser().'<hr>';
- trait支持继承
//2、trait支持继承
trait Demo{
public $name='李四';
public function getUser()
{
//__METHOD__:返回该方法被定义时的名字(区分大小写)
return 'trait method name : ' . __METHOD__;
}
}
class Demo1{
use Demo;
}
class Demo2 extends Demo1{
}
echo (new Demo2)->getUser().'<br>';
echo (new Demo2)->name.'<hr>';
//静态属性及方法
trait Demos{
public static $name='张三';
public static function get()
{
//__METHOD__:返回该方法被定义时的名字(区分大小写)
return 'trait method name : ' . __METHOD__;
}
}
//可以使用抽象类(abstract)使用strait
abstract class Demo3{
use Demos;
}
// 给用户提供的工作类/实现,应该尽可能的简单,可以将一些实现细节进行隐藏
class Demo4 extends Demo3{
}
//静态属性的调用方法为"类名::属性名"
echo Demo4::get().'<br>';
echo Demo4::$name;
- trait扩展
//3、trait扩展
trait Demo{
public function getUser(){
return '姓名:'.$this->name.',年龄:'.$this->age.'岁';
}
}
trait Demos{
public function getUsers(){
//get_class_vars() 函数返回由类的默认属性组成的数组;参数为类名
return sprintf('<pre>%s</pre>', print_r(get_class_vars(self::class), true));
}
}
//同时引入多个trait,用,隔开;trait支持功能整合,trait中允许再引入trait
trait tDemo{
use Demo,Demos;
}
class Demo1{
use tDemo;//tDemo中已经整合了Demo和Demos,此时只需要引入一个tDemo即可
protected $name='张三';
protected $age='30';
}
echo (new Demo1)->getUser().'<br>';
echo (new Demo1)->getUsers();
- trait成员的命名冲突
//4、trait成员的命名冲突
trait Demo{
public function getUser(){
return '姓名:'.$this->name.',年龄:'.$this->age.'岁';
}
}
trait Demos{
public function getUser(){
//get_class_vars() 函数返回由类的默认属性组成的数组;参数为类名
return sprintf('<pre>%s</pre>', print_r(get_class_vars(self::class), true));
}
}
trait tDemo1{
protected $profession='司机';
public function getUser(){
// return __METHOD__;
return '姓名:'.$this->name.',年龄:'.$this->age.'岁,职业:'.$this->profession;
}
}
//同时引入多个trait,用,隔开;trait支持功能整合,trait中允许再引入trait
trait tDemo{
use Demo,Demos,tDemo1{//Demo和Demos中的方法名冲突,先替代,然后起别名
//替代:用Demo::getUser将Demos::getUser替换掉,也就是只有Demo中的方法起作用
Demo::getUser insteadOf Demos;
Demos::getUser insteadOf tDemo1;//用Demos::getUser将tDemo1::getUser替换掉
//别名:给Demos::getUser起别名
Demos::getUser as getUsers;
tDemo1::getUser as td;//给tDemo1::getUser起别名
}
}
class Demo1{
use tDemo;//tDemo中已经整合了Demo和Demos,此时只需要引入一个tDemo即可
protected $name='张三';
protected $age='30';
}
echo (new Demo1)->getUser().'<br>';
echo (new Demo1)->getUsers().'<br>';
echo (new Demo1)->td();
//2个以上的trait成员命名冲突时如何做???
- trait与interface组合
//5、trait与interface组合
//创建接口,在创建前先判断当前接口是否存在
//interface_exists() 函数检查接口是否已被定义
if (!interface_exists('iDemo')){
interface iDemo {
// 创建一个静态抽象方法
//接口的方法必须是public(默认是public),且接口中只能定义方法名(含参数),不能有函数体
public static function index();
public static function user();
}
}
//用trait实现接口中的方法
trait tDemo{
// 将抽象类的实现代码写到trait中
public static function index(){
return __METHOD__;
}
public static function user(){
return 'Hello Word!';
}
}
//要实现一个接口,需使用 implements 操作符,类中必须实现接口中定义的所有方法
abstract class work implements iDemo{
use tDemo;
}
class works extends work{}
echo works::index().'<br>';
echo works::user();
interface常用场景
//interface:接口;接口完全的分离了:设计(接口)与实现(实现类)
//1、单接口的实现
interface A{
//接口中只能定义方法名(含参数),不能有函数体;接口的方法必须是public(默认public)
public function write();
//接口中不能有属性,但可以定义常量
const NAME='胡八一';
//接口不能进行实例化,但可以有构造方法
// public function __construct();
}
//要实现一个接口,使用 implements 操作符,类中必须实现接口中定义的所有方法
class userA implements A{
protected $age=33;
public function write(){
return '姓名:'.A::NAME.',年龄:'.$this->age.'岁';
}
}
echo (new userA)->write().'<hr>';
//2、接口继承、实现多个接口
interface B extends A{
//B接口继承A接口
const NATION='CHINA';
}
interface C extends A,B{
//C接口继承A和B接口
public static function work();
//多个接口进行整合,形成一个统一的接口,再用一个类实现
}
//一个类可以同时实现多个接口,实现多个接口时,接口中的方法不能有重名
//实现类
class userB implements C{
public function write(){
return '姓名:'.A::NAME.',国籍:'.B::NATION;
}
public static function work(){
return __METHOD__;
}
}
echo (new userB)->write().'<br>';
echo (new userB)->work().'<hr>';
// php是典型的单继承式语言
// 接口之间允许继承,并用支持多继承
// 可以有二种实现方案:
// 1)将多个接口进行整合,形成一个统一的接口,然后用一个实现类来实现它
// 2)一个实现类同时实现多个接口,实现类的功能组合,是一种横向功能扩展
抽象类与interface的区别与联系
//abstract抽象类: 部分的分离了: 设计(抽象类)与实现(工作类)
abstract class user{
protected $name='张三';
//抽象类中的方法可以有抽象方法,也可以有非抽象方法
public function work(){
return __METHOD__;
}//抽象方法:只其调用方式(参数),没有具体的实现过程,即没有函数体
abstract function write();
}
// 抽象类禁止实例化
// 抽象类必须使用它的子类才可以访问/工作
class user1 extends user{
public function write(){
return $this->name;
}
}
echo (new user1)->work().'<br>';
echo (new user1)->write();
- 抽象类中至少有一个抽象方法,且前面必须加abstract
- 接口成员的属性只能是常量;接口中的方法都是抽象方法,无函数体,且都必须是public
- 接口类和抽象类本身均不能实例化,必须通过类进行继承;且继承后必须全部实现所有抽象方法
- 抽奖案例
简单抽奖
//设置抽奖接口
interface drawId{
public static function getDrawId($min,$max);
}
//公共方法:实现抽象接口方法
trait tDrawId{
public static function getDrawId($min,$max){
//mt_rand()生成随机整数
return mt_rand($min,$max);
}
}
//实现工作类
class Draw implements drawId{
use tDrawId;
public static function award($prizes,$id){
return $prizes[$id];
}
}
$prizes=['电脑','手机','平板','相机','音箱','耳机','U盘'];
$id=Draw::getDrawId(0,6);
$prize=Draw::award($prizes,$id);//随机输出$prizes中的值
echo '你的奖品是:'.$prize;
双色球
<?php
//抽奖案例:双色球
//设置抽奖接口
interface drawId{
public static function getDrawId($min,$max);
}
//公共方法:实现抽象接口方法
trait tDrawId{
public static function getDrawId($min,$max){
//mt_rand()生成随机整数
return mt_rand($min,$max);
}
}
// 抽象类: 彩票(lottery)
abstract class Lottery implements drawId{
//引入trait
use tDrawId;
//生成中奖需要的编号,$num表示需要的数量
protected static function createBalls($min,$max,$num){
//1、按照开奖规则生成指定步长和数量的编号
//range() 函数创建一个包含指定范围的元素的数组
$allBalls=range($min,$max,1);//1为规定元素之间的步进制。默认是 1
//2、蓝色球,生成$num=1个
//array_rand(array,number):array必需,规定数组;number可选,规定返回多少随机键名
//如果选出的元素不止一个,则返回包含随机键名的数组,否则返回该元素的键名
if($num===1) return $allBalls[array_rand($allBalls)];//array_rand($allBalls)返回的是元素的键名,需要根据键名获取对应的值
//3、红色球:随机6个球的编号
$redBallsKeys=array_rand($allBalls,6);//返回6个随机元素的键名数组
//根据键名获取对应的值
$redBalls=[];
foreach($redBallsKeys as $key){
$redBalls[]=$allBalls[$key];
}
return $redBalls;
}
//抽象方法:生成一个中奖号:6个红色球+1个蓝色球
abstract protected static function doubleBall($redRule,$blueRule);
//抽象方法:生成一组试机号
abstract protected static function doubleBalls($redRule,$blueRule,$range);
}
// 工作类: 抽奖(DrawLottery);用抽象类的子类去实现、访问
class DrawLottery extends Lottery{
//生成一个中奖号:6个红色球+1个蓝色球
public static function doubleBall($redRule,$blueRule){
//红色球规则:[1,33,6],1-33之间取随机6个数
$redBalls=self::createBalls(...$redRule);
sort($redBalls);//sort() 函数对数值数组进行升序排序
//蓝色球规则:[1,16,1],1-16之间取随机1个数
$blueBall=self::createBalls(...$blueRule);
//红色+蓝色组成一个完整的中奖号
//array_push() 向数组尾部插入一个或多个元素
array_push($redBalls,$blueBall);//在$redBalls数组尾部添加一个值$blueBall
//最终7个号码在$redBalls中
return $redBalls;
}
//生成一组试机号
public static function doubleBalls($redRule,$blueRule,$range){
// 随机生成试机号的数量
$count = self::getDrawId(...$range);
$randBalls = [];
for ($i = 0; $i < $count; $i++) {
$randBalls[] = self::doubleBall($redRule, $blueRule);
}
// 返回最终生成一组开奖号
return $randBalls;
}
}
$draw = DrawLottery::doubleBall([1,33,6], [1,16,1]);
// print_r($draw);
$randBalls = DrawLottery::doubleBalls([1,33,6], [1,16,1],[1,6]);
// print_r($randBalls);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>双色球开奖啦</title>
<style>
.container{
display:grid;
grid-template-columns:repeat(7,40px);
gap:15px;
margin-bottom:15px;
}
.container >span{
width:30px;
height:30px;
border-radius:50%;
color:#fff;
font-weight:700;
text-align:center;
line-height:30px;
}
.container >span:nth-of-type(-n+6){
background-color:red;
}
.container >span:last-of-type{
background-color:blue;
}
</style>
</head>
<body>
<h2>模拟双色球开奖</h2>
<h3>今日开奖号码: <small><?php echo date('Y年m月d日 H:i:s', time()); ?></small></h3>
<div class="container">
<?php foreach ($draw as $item) :?>
<span><?php echo $item ?></span>
<?php endforeach ?>
</div>
<h3>今日试机号: </h3>
<?php foreach ($randBalls as $draws) :?>
<div class="container">
<?php foreach ($draw as $item) :?>
<span><?php echo $item ?></span>
<?php endforeach ?>
</div>
<?php endforeach ?>
</body>
</html>