开发者学堂课程【PHP 进阶教程-由浅入深掌握面向对象开发-第三阶段:PDO 读操作】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/713/detail/12735
PDO 读操作
内容介绍:
一、介绍
二、步骤
三、小结
一、介绍
1、目标:
掌握PDO对查询操作的实现,如何利用PDO将数据库中的数据查询出来,理解类中产生其他类对象的原理(本质上已经学习过:工厂模式就是调用方法来产生其他类的对象),实现数据库的查询操作。
2、概念:
查询操作:通过执行SQL指令后从数据库获得相应的数据,然后对数据加工变成PHP可识别的格式(数组可以,对象也可以,但是若是对象中的数据没有显出则不能操作)
(1)PDO:.query()方法只能执行SQL,并不能直接解析结果,返回一个PDOStatement类对象(如果成功就返回PDOStatement类对象,如果错误就返回false)
(2)PDOStatement::fetch()系列方法从对象中实现数据获取(拿到一个PDOStatement类对象,PDOStatement类对象下有一些fetch()方法可以获取数据)
有两个常用方法:
fetch:获取一条记录
fetchAll:获取全部记录,不需要再循环获取,能够自己提供方法。
在fetch中有一个参数:
(3)FETCH_STYLE:通过常量设计的方式实现获取数据的不同效果。从数据库中获取数据时获取表可以是索引数组或关联数组,甚至为对象。所以FETCH_STYLE可以控制拿到数据的模式。
二、步骤
1、初始化数据库连接
2、组织SQL指令并通过PDO:.query()执行
3、检查可能出现的SQL语法错误
4、通过PDOStatement类按照具体需求实现数据解析
三、示例
1、查询是建立在连接之上,因此需要使用到前面封装的初始化功能
function pdo_init(){
$pdo = @new PDO( 'mysql: host=localhost;port=3306; dbname=db_2' , ' root' , ' root');
if( ! $pdo){
exit('数据库连接认证失败! ');
}
#返回得到的PDO对象
return $pdo;
}
2、查询的SQL也是可能出现问题的部分,因此同样需要进行错误检查︰另外PDO查询使用的是PDO:.query()方法实现。
整个代码与之前exec部分相似,内容也相同,只是调用方法不同。所以此时解决方法:编写统一方法判定是写操作还是查操作,然后调用不同的方法,该方法对于用户比较简单,用户不需要考虑sql该调用哪种方法,可以直接调用执行;另一种方式是写操作与读操作分开,exec执行写操作,query执行查询操作返回对象。为了不改动先前代码,应该在此处增加一个方法进行query查询。
function pdo_query($pdo, $sql){
#调用PDO对象的方法执行读SQL
$stmt = $pdo->query(ssq1);
#错误判定
if(false === $stmt){
#取出错误细信息
echo 'SQL错误:
';
echo '错误代码为: ' . $pdo->errorCode( . '
';
echo '错误原因为: ’ . $pdo->errorInfo()[2];
exit;
#返回执行结果:PDOStatement类对象
return $stmt;
}
#取出错误细信息
演示:
在33pdo_func.php代码中继续输入
#封装执行:读操作(SQL执行和语法错误检查)
粘贴上述代码
再来验证获取得到的是一个对象,输入
$pdo = pdo_init();
$stmt = pdo_query($pdo,’select * from t_28’);
var_dump($stmt);
访问网址33pdo_func.php结果显示为一个PDOStatement对象:
object(PDOStatement)#2(1){[“queryString”]=>string(18)”select * from t_28”}
说明SQL没有语法问题。但是此时获取到的对象中没有数据,不能直接通过对象进行php读取,因此需要进行解析,将对象调用相应的方法实现解析。
3、此时查询出来的结果是一个对象,不能提供任何PHP可访问的数据结果,还需要对结果进行处理。而我们查询数据的时候通常是两种操作:根据具体条件获取一条记录或者多条记录(根据用户需求,用户SQL查一条则查一条),因此返回的数据是不同的。解决方案也有多种方式:
①创建多个函数来实现不同效果
②创建一个函数,但是通过参数来控制实现不同效果
#数据解析
function pdo_get($stmt, $only = true){
#$stmt是PDO查询得到的对象,$only代表默认只获取一条记录
#安全判定
if(!$stmt instanceof PDOStatement) return false;
# PDOStatement类中提供了两种方法分别去获取一条和多条记录
#判定条件
if($only){
#获取一条记录PDOStatement::fetch():返回一维数组
return $stmt->fetch();
}else{
#获取多条记录PDOStatement ::fetchAll():返回二维数组,一个维度代表一条记录
return $stmt->fetchAll();
演示:
粘贴在代码$pdo = pdo_init();
$stmt = pdo_query($pdo,’select * from t_28’);
var_dump($stmt);上方
删除掉代码var_dump($stmt);
输入var_dump(pdo_get($stmt));
刷新访问页面结果显示:
array(6){[“id”]=>string(1)”2”[0]=>string(1)”2”[“stu_no”]=>string(8)”00000002”[1]=>string(8)”00000002”[“stu_name”]=>string(4)”Jack”[2]=>string(4)”Jack”}
结果是一个关联索引并行的数组。
数据库中select * from t_28
原本只有3个字段,现在有6个字段。
如果需要获取多条记录,修改代码var_dump(pdo_get($stmt,false));
访问页面结果显示如图:
得到的是一个对应的二维数组,查出了5条记录,每个记录都是数组,同样有关联和索引。
调用方法拿到数组后就可以进行显示数据。删除测试代码:
$pdo = pdo_init();
$stmt = pdo_query($pdo,’select * from t_28’);
var_dump(pdo_get($stmt,false));
以上完成了PDO封装函数实现写操作。
4、此时从功能上来讲,只要顺序调用以上几个方法即可完成
$pdo = pdo_init();
#初始化
#查询
$sql = 'select * from t_40 where条件';
$stmt = pdo_query($pdo , $sql);
#获取一条记录
$row = pdo_get($stmt);
#获取多条记录
$rows = pdo_get($stmt,false);
演示:
接着创建新文件35pdo_read.php实现封装函数实现读操作,编辑代码:
#PDO封装函数实现读操作
#引入函数文件
include ‘33pdo_func.php’;
#连接认证
$pdo = pdo_init();
#准备SQL
$sql = “select * from t_40”;
#执行SQL
$stmt = pdo_query($pdo,$sql);
#解析结果
$row = pdo_get($stmt);
var_dump($row);
访问网址35pdo_read.php,结果显示
array(10) ( ["id”]=> string(1)"1”[0]=> string(1)"1”[“name"=> string(6)"鸣人”[1]=> string(6)"鸣人”[“gender”]=> string(3)"男" [2]=>string(3)"男"[“age”]=>string(2) "21”[3]=> string(2) "21”[“class_name"]=> string(10)"木叶1班”[4]=>string(10)"木叶1班"}
拿到数据,若是想要拿到多条修改代码$row = pdo_get($stmt,false);
刷新页面结果显示:
5、fetch系列方法默认返回的数据是重复的:数据的索引方式和关联方式各出现一次,而实际在进行开发数据展示时通常是通过数据表字段名字作为下标进行数据查看,所以此时可以通过设定fetch系列的条件fetch_style来实现
mixed PDOStatement ::([int $fetch_style[, int $cursor_orientation = PDO::FETCH_ORI_NEXT [, int
$fetch_stylet, int $cursor_orientation = PDO::FETCH_ORI_NEXT [, int $cursor_offset =0 ]]])
//$fetch_style是有默认值的参数,代表一个模式:显示方式。非常多参数都是通过PDO的类常量控制。
从一个PDOStatement对象相关的结果集中获取下一行。fetch_style参数决定POD如何返回行。
fetch_style:
控制下一行如何返回给调用者。此值必须是PDO:FETCH_*系列常量中的一个,缺省为PDO::ATTR_DEFAULT_FETCH_MODE的值(默认为PDO:.FETCH_BOTH ).
PDO:FETCH_ASSOC:返回一个索引为结果集列名的数组。字段名作为下标的关联数组
PDO::FETCH_BOTH(默认)︰返回一个索引为结果集列名和以0开始的列号的数组。
PDO:FETCH_BOUND:返回TRUE,并分配结果集中的列值给PDOStatement::bindColumn()方法绑定的PHP变量。
PD0..FETCH_CLASS:返回一个请求类的新实例,映射结果集中的列名到类中对应的属性.
想要使用fetch_style可以根据系统提供的方式来修改pdo_get函数,在后面再增加一个默认参数即可。
function pdo_get($stmt , $only = true,$fetch_style = PDO::FETCH_ASSOC){
# fetch_style
默认使用关联数组返回
#判定条件
if($only){
#获取一条记录PDOstatement: :fetch():返回一维数组
return $stmt->fetch($fetch_style);
}else{
#获取多条记录PDOStatement::fetchAll():返回二维数组,一个维度代表一条记录
return $stmt->fetchAll($fetch_style);
}
在代码33pdo_func.php中找到代码function pdo_get($stmt,$only=true){}
修改为
function pdo_get($stmt,$only=true,$fetch_style = PDO::FETCH_ASSOC){}
代码不受影响,需要将fetch_style放到return $stmt->fetch()中改变fetch模式,即
return $stmt->fetch(fetch_style);
return $stmt->fetchAll($fetch_style);
在读操作中调用的就为该函数,所以此时并没有传到后面,为默认。
现在每一条记录都有10个字段,再刷新页面查看结果:
每一个记录中有5个字段,并且只有字段对应的值,没有索引对应的值的元素存在。
理论上数据拿到的越全,解析的方式越多越方便,但是意味着效率更低。如果明确就是关联数组,则不需要再获取其它。
以上就介绍了fetch模式。若想要了解更多可以再PHP Manual中找到fetch_style,查看更多具体说明,例如:
PDO:FETCH_NUM:返回一个索引为以0开始的结果集列号的数组
PDOFETCH_OBJ:返回一个属性名对应结果集列名的匿名对象
PDOFETCH_CLASS:返回一个请求类的新实例,映射结果集中的列名到类中对应的属性名。如果fetch_style包含PDO:FETCH_CLASSTYPE(例如: PDO:FETCH_CLASS / PDO:FETCH_CLASSTYPE),则类名由第一列的值决定。
但是使用最多的为:
PDO:FETCH_ASSOC:返回一个索引为结果集列名的数组
以上就是读操作关于模式的处理,保证数据的有效性,减少服务器压力。
三、小结
1、查询操作是通过PDO:query()执行查询SQL得到PDOStatement对象,然后PDOStatement对象下有一系列fetch方法可以实现数据查询,得到PHP可以识别的数组数据。(数据可以进行控制,需要数组则为数组,需要对象则为对象:对象相当于查询出的结果变为元素,属性也为键值对,也有名字与值,相当于拿到字段中的名字做属性名,字段取出对应值做属性值。)
2、PDO实现查询通常也需要进行二次封装(不做二次封装会导致在操作中编写多次。若是数据库中信息进行修改,写操作与读操作都需要进行修改),保证SQL执行安全,也方便用户获取目标数据。