本篇文章给大家带来了php中pdo对象的相关知识,php 数据对象(pdo)扩展为php访问数据库定义了一个轻量级的一致接口,应该怎样去理解使用,下面我们一起来看一下,希望对大家有帮助。
对pdo对象的认识1.1 简介 php 数据对象 (pdo) 扩展为php访问数据库定义了一个轻量级的一致接口。实现 pdo 接口的每个数据库驱动可以公开具体数据库的特性作为标准扩展功能。 注意利用 pdo 扩展自身并不能实现任何数据库功能;必须使用一个 具体数据库的 pdo 驱动 来访问数据库服务。
pdo 提供了一个 数据访问 抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。 pdo 不提供 数据库 抽象层;它不会重写 sql,也不会模拟缺失的特性。如果需要的话,应该使用一个成熟的抽象层。
1.2 安装配置方法pdo 和所有主要的驱动作为共享扩展随 php 一起发布,要激活它们只需简单地编辑 php.ini 文件:extension=php_pdo.dll
注意:这一步在 php 5.3及更高版本中不是必须的,对于 pdo 不再需要做为一个 dll 文件。
若要连接数据库,还需要去掉与pdo相关的数据库扩展前面的”;号,然后重启apache服务器即可。extension=php_pdo.dllextension=php_pdo_firebird.dllextension=php_pdo_informix.dllextension=php_pdo_mssql.dllextension=php_pdo_mysql.dllextension=php_pdo_oci.dllextension=php_pdo_oci8.dllextension=php_pdo_odbc.dllextension=php_pdo_pgsql.dllextension=php_pdo_sqlite.dll
1.3 pdo类1.3.1 pdo::__constructpdo::__construct — 创建一个表示数据库连接的 pdo 实例
说明pdo::__construct ( string $dsn , string $username = ? , string $password = ? , array $driver_options = ? )
参数 dsn
数据源名称或叫做 dsn,包含了请求连接到数据库的信息。 通常,一个 dsn 由 pdo 驱动名、紧随其后的冒号、以及具体 pdo 驱动的连接语法组成。示例:mysql:host=localhost;dbname=pxscj
username
dsn字符串中的用户名。对于某些pdo驱动,此参数为可选项。password
dsn字符串中的密码。对于某些pdo驱动,此参数为可选项。driver_options
一个具体驱动的连接选项的键=>值数组。返回值
成功则返回一个pdo对象。示例<?php/* connect to an odbc database using driver invocation */$dsn = 'mysql:host=localhost;dbname=pxscj';$user = 'user';$password = '123456';try { $dbh = new pdo($dsn, $user, $password);} catch (pdoexception $e) { echo 'connection failed: ' . $e->getmessage();}?>
1.3.2 pdo::execpdo::exec — 执行一条 sql 语句,并返回受影响的行数
说明pdo::exec ( string $statement ) : int
参数 statement
要被预处理和执行的 sql 语句。见解:此处statement应妥善处理用户的输入防止被sql注入
返回值
pdo::exec() 返回受修改或删除 sql 语句影响的行数。如果没有受影响的行,则 pdo::exec() 返回 0。示例<?php$db=new pdo("mysql:host=localhost;dbname=pxscj","user","123456");$delete_sql="delete from userinfo where username='user1'"; //注销自己的sql语句$affected=$db->exec($delete_sql); //执行没有返回的sql语句$delete_sqlif($affected) //如果受影响记录数不为0 echo 注销用户成功!;else echo 注销用户失败!;?>
1.3.3 pdo::querypdo::query — 执行 sql 语句,以 pdostatement 对象形式返回结果集
说明public pdo::query ( string $statement ) : pdostatement
参数 statement
需要准备、执行的 sql 语句。返回值
pdo::query() 返回 pdostatement 对象,或在失败时返回 false。示例<?php$db=new pdo("mysql:host=localhost;dbname=pxscj","user","123456");$query="select * from kcb"; //sql语句foreach($db->query($query) as $row) { //执行sql语句$query--执行有结果集的sql语句 echo 课程号:.$row[0].<br>; //返回的是一个pdostatement类(型)的对象 echo 课程名:.$row[1].<br>; //还可以用pdostatement类的方法fetch()行读 echo 开课日期:.$row[2].<br>; echo 学时:.$row[3].<br><br>;}?>
1.3.4 pdo::preparepdo::prepare — 准备要执行的语句,并返回语句对象
说明public pdo::prepare ( string $statement , array $driver_options = array() ) : pdostatement
为pdostatement::execute() 方法准备待执行的 sql 语句。 sql 语句可以包含零个或多个参数占位标记,格式是命名(:name)或问号(?)的形式,当它执行时将用真实数据取代。 在同一个 sql 语句里,命名形式和问号形式不能同时使用;只能选择其中一种参数形式。 注:用参数形式绑定用户输入的数据,不要直接字符串拼接到查询里,防sql注入
参数 statement
必须是对目标数据库服务器有效的 sql 语句模板。
driver_options
数组包含一个或多个 key=>value 键值对,为返回的 pdostatement 对象设置属性。
返回值
如果数据库服务器完成准备了语句, pdo::prepare() 返回 pdostatement 对象。 如果数据库服务器无法准备语句, pdo::prepare() 返回 false 或抛出 pdoexception (取决于 错误处理器)。
注:模拟模式下的 prepare 语句不会和数据库服务器交互,所以 pdo::prepare() 不会检查语句。示例$db=new pdo(mysql:host=localhost;dbname=pxscj,user,123456);$in_sql=insert into userinfo(username,password,sex,age,email) values(?,?,?,?,?); $in_result=$db->prepare($in_sql); //预处理sql语句$in_sql$userid=php3; $pwd1=111111; $sex=0; $age=36; $email=php3@qq.com;$in_result->bindparam(1, $userid); //pdostatement的bindparam()的作用是绑定参数给execute()$in_result->bindparam(2, $pwd1); //sql语句使用问号参数时--bindparam()第一个参数是问号索引偏移(第几个)$in_result->bindparam(3, $sex); //bindparam()第二个参数是赋值给sql语句参数(问号)的变量$in_result->bindparam(4, $age); $in_result->bindparam(5, $email);$in_result->execute(); //执行经过预处理的sql语句$in_resultif($in_result->rowcount()==0) //用pdostatement的rowcount()返回结果集行的总数 echo 插入记录失败!;else echo 插入记录成功!;
1.3.5 pdo::begintransactionpdo::begintransaction — 启动一个事务
说明pdo::begintransaction():bool
返回值
成功时返回 true, 或者在失败时返回 false。1.3.6 pdo::rollbackpdo::rollback — 回滚一个事务
说明pdo::rollback():bool
回滚由 pdo::begintransaction() 发起的当前事务。如果没有事务激活,将抛出一个 pdoexception 异常。
如果数据库被设置成自动提交模式,此函数(方法)在回滚事务之后将恢复自动提交模式。
返回值
成功时返回 true, 或者在失败时返回 false。示例<?php/* 开始一个事务,关闭自动提交 */$dbh->begintransaction();/* 更改数据库架构和数据 */$sth = $dbh->exec(drop table fruit);$sth = $dbh->exec(update dessert set name = 'hamburger');/* 识别错误且回滚更改 */$dbh->rollback();/* 此时数据库连接恢复到自动提交模式 */?>
1.3.7 内部函数说明pdo::begintransaction — 启动一个事务pdo::commit — 提交一个事务pdo::__construct — 创建一个表示数据库连接的 pdo 实例pdo::errorcode — 获取跟数据库句柄上一次操作相关的 sqlstatepdo::errorinfo — fetch extended error information associated with the last operation on the database handlepdo::exec — 执行一条 sql 语句,并返回受影响的行数pdo::getattribute — 取回一个数据库连接的属性pdo::getavailabledrivers — 返回一个可用驱动的数组pdo::intransaction — 检查是否在一个事务内pdo::lastinsertid — 返回最后插入行的id或序列值pdo::prepare — 准备要执行的语句,并返回语句对象pdo::query — 执行 sql 语句,以 pdostatement 对象形式返回结果集pdo::quote — 为 sql 查询里的字符串添加引号pdo::rollback — 回滚一个事务pdo::setattribute — 设置属性
1.4 pdostatement类1.4.1 pdostatement::bindparampdostatement::bindparam — 绑定一个参数到指定的变量名
说明pdostatement::bindparam ( mixed $parameter , mixed &$variable , int $data_type = pdo::param_str , int $length = ? , mixed $driver_options = ? ):bool
绑定一个php变量到用作预处理的sql语句中的对应命名占位符或问号占位符。 不同于 pdostatement::bindvalue() ,此变量作为引用被绑定,并只在 pdostatement::execute() 被调用的时候才取其值。
返回值
成功时返回 true, 或者在失败时返回 false。参数 parameter
参数标识符。对于使用命名占位符的预处理语句,应是类似 :name 形式的参数名。对于使用问号占位符的预处理语句,应是以1开始索引的参数位置。variable
绑定到 sql 语句参数的 php 变量名。data_type
使用 pdo::param_* 常量明确地指定参数的类型。要从一个存储过程中返回一个 inout 参数,需要为 data_type 参数使用按位或操作符去设置 pdo::param_input_output 位。length
数据类型的长度。为表明参数是一个存储过程的 out 参数,必须明确地设置此长度。driver_options示例<?php/* 通过绑定的 php 变量执行一条预处理语句 */$calories = 150;$colour = 'red';$sth = $dbh->prepare('select name, colour, calories from fruit where calories < :calories and colour = :colour');$sth->bindparam(':calories', $calories, pdo::param_int);$sth->bindparam(':colour', $colour, pdo::param_str, 12);$sth->execute();?>
1.4.2 pdostatement::executepdostatement::bindparam — 绑定一个参数到指定的变量名
说明pdostatement::execute ( array $input_parameters = ? ) : bool
执行预处理过的语句。如果预处理过的语句含有参数标记,必须选择下面其中一种做法:
1)调用 pdostatement::bindparam() 绑定 php 变量到参数标记:如果有的话,通过关联参数标记绑定的变量来传递输入值和取得输出值
2)或传递一个只作为输入参数值的数组
返回值
成功时返回 true, 或者在失败时返回 false。参数 input_parameters示例<?php/* 通过传递一个含有插入值的数组执行一条预处理语句 */$calories = 150;$colour = 'red';$sth = $dbh->prepare('select name, colour, calories from fruit where calories < :calories and colour = :colour');$sth->execute(array(':calories' => $calories, ':colour' => $colour));?>
1.4.3 pdostatement::fetchpdostatement::fetch — 从结果集中获取下一行
说明pdostatement::fetch ( int $fetch_style = ? , int $cursor_orientation = pdo::fetch_ori_next , int $cursor_offset = 0 ):mixed
从一个 pdostatement 对象相关的结果集中获取下一行。fetch_style 参数决定 pod 如何返回行。
返回值
此函数(方法)成功时返回的值依赖于提取类型。在所有情况下,失败都返回 false 。参数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 变量。pdo::fetch_class:返回一个请求类的新实例,映射结果集中的列名到类中对应的属性名。如果 fetch_style 包含 pdo::fetch_classtype(例如:pdo::fetch_class | pdo::fetch_classtype),则类名由第一列的值决定pdo::fetch_into:更新一个被请求类已存在的实例,映射结果集中的列到类中命名的属性pdo::fetch_lazy:结合使用 pdo::fetch_both 和 pdo::fetch_obj,创建供用来访问的对象变量名pdo::fetch_num:返回一个索引为以0开始的结果集列号的数组pdo::fetch_obj:返回一个属性名对应结果集列名的匿名对象
cursor_orientation
对于 一个 pdostatement 对象表示的可滚动游标,该值决定了哪一行将被返回给调用者。此值必须是pdo::fetch_ori_* 系列常量中的一个,默认为 pdo::fetch_ori_next。offset
对于一个 cursor_orientation 参数设置为 pdo::fetch_ori_abs 的pdostatement 对象代表的可滚动游标,此值指定结果集中想要获取行的绝对行号。示例<?php$sth = $dbh->prepare(select name, colour from fruit);$sth->execute();/* 运用 pdostatement::fetch 风格 */print(pdo::fetch_assoc: );print(return next row as an array indexed by column name\n);$result = $sth->fetch(pdo::fetch_assoc);print_r($result);print(\n);?>
1.4.4 pdostatement::executepdostatement::fetchall — 返回一个包含结果集中所有行的数组
说明pdostatement::fetchall ( int $fetch_style = ? , mixed $fetch_argument = ? , array $ctor_args = array() ):array
返回值
pdostatement::fetchall() 返回一个包含结果集中所有剩余行的数组。此数组的每一行要么是一个列值的数组,要么是属性对应每个列名的一个对象。
注:使用此方法获取大结果集将导致系统负担加重且可能占用大量网络资源。与其取回所有数据后用php来操作,倒不如考虑使用数据库服务来处理结果集。例如,在取回数据并通过php处理前,在 sql 中使用 where 和 order by 子句来限定结果。参数 fetch_style
控制返回数组的内容如同 pdostatement::fetch()一样。默认为 pdo::attr_default_fetch_mode 的值( 其缺省值为 pdo::fetch_both )想要返回一个包含结果集中单独一列所有值的数组,需要指定 pdo::fetch_column 。通过指定 column-index 参数获取想要的列。fetch_argument
根据 fetch_style 参数的值,此参数有不同的意义:
pdo::fetch_column:返回指定以0开始索引的列。
pdo::fetch_class:返回指定类的实例,映射每行的列到类中对应的属性名。
pdo::fetch_func:将每行的列作为参数传递给指定的函数,并返回调用函数后的结果。ctor_args
当 fetch_style 参数为 pdo::fetch_class 时,自定义类的构造函数的参数。示例<?php$sth = $dbh->prepare(select name, colour from fruit);$sth->execute();/* 获取结果集中所有剩余的行 */print(fetch all of the remaining rows in the result set:\n);$result = $sth->fetchall();print_r($result);?>
1.4.5 pdostatement::rowcountpdostatement::rowcount — 返回受上一个 sql 语句影响的行数
说明pdostatement::rowcount():int
pdostatement::rowcount() 返回上一个由对应的 pdostatement 对象执行delete、 insert、或 update 语句受影响的行数。
如果上一条由相关 pdostatement 执行的 sql 语句是一条 select 语句,有些数据可能返回由此语句返回的行数。但这种方式不能保证对所有数据有效,且对于可移植的应用不应依赖于此方式。
返回值
返回行数。示例<?php/* 从 fruit 数据表中删除所有行 */$del = $dbh->prepare('delete from fruit');$del->execute();/* 返回被删除的行数 */print(return number of rows that were deleted:\n);$count = $del->rowcount();print(deleted $count rows.\n);?>
1.4.6 内部函数说明pdostatement::bindcolumn — 绑定一列到一个 php 变量pdostatement::bindparam — 绑定一个参数到指定的变量名pdostatement::bindvalue — 把一个值绑定到一个参数pdostatement::closecursor — 关闭游标,使语句能再次被执行。pdostatement::columncount — 返回结果集中的列数pdostatement::debugdumpparams — 打印一条 sql 预处理命令pdostatement::errorcode — 获取跟上一次语句句柄操作相关的 sqlstatepdostatement::errorinfo — 获取跟上一次语句句柄操作相关的扩展错误信息pdostatement::execute — 执行一条预处理语句pdostatement::fetch — 从结果集中获取下一行pdostatement::fetchall — 返回一个包含结果集中所有行的数组pdostatement::fetchcolumn — 从结果集中的下一行返回单独的一列。pdostatement::fetchobject — 获取下一行并作为一个对象返回。pdostatement::getattribute — 检索一个语句属性pdostatement::getcolumnmeta — 返回结果集中一列的元数据pdostatement::nextrowset — 在一个多行集语句句柄中推进到下一个行集pdostatement::rowcount — 返回受上一个 sql 语句影响的行数pdostatement::setattribute — 设置一个语句属性pdostatement::setfetchmode — 为语句设置默认的获取模式。
1.5 用法及小结 以上pdo类及pdostatement类的说明摘录自php开发手册,详细描述只摘录了常用的几个内部函数。实话实说对于一个程序员最好的提升技术的方法之一就是看文档,通过查阅文档可以解决我们在开发中遇到的许多问题,而且通过文档我们可以知道很多api使用的细节和注意点,帮助我们规避很多错误。总而言之遇到问题看文档,多百度,多看博客,多总结,这才是长久的学习之道。
多说不做也是不行的,练习才是技术提升的必由之路,练习实践才可以在其中发现问题,提升自己,下面代码是我对pdo的一些常见用法的整理:
try { $db=new pdo(mysql:host=localhost;dbname=pxscj,user,123456); }catch (pdoexception $e) { echo 数据库连接失败:.$e->getmessage(); }$db->exec(set names utf-8); //插入 $query=insert into kcb values('606','php程序设计',6,48,3); if($affcount=$db->exec($query)) { echo 插入成功,受影响条数为:.$affcount.<br><br>; }//查询$query=select * from kcb; foreach($db->query($query) as $row) { echo 课程号:.$row[0].<br>; echo 课程名:.$row[1].<br>; echo 开课日期:.$row[2].<br>; echo 学时:.$row[3].<br><br>;}//事务处理try { $db->exec(set names utf-8); $db->begintransaction(); $affrows=$db->exec(insert into kcb values('506','uml系统分析',5,48,3)); if(!$affrows) throw new pdoexception(插入失败1); $affrows=$db->exec(insert into kcb values('606','php程序设计',6,32,2)); if(!$affrows) throw new pdoexception(插入失败2); echo 插入成功!; $db->commit(); }catch (pdoexception $e) { echo $e->getmessage(); $db->rollback(); //回滚(要么成功要么失败)}//prepare 可以防sql注入$in_sql=insert into userinfo(username,password,sex,age,email) values(?,?,?,?,?); $in_result=$db->prepare($in_sql); $userid=php3; $pwd1=111111; $sex=0; $age=36; $email=php3@qq.com;$in_result->bindparam(1, $userid); $in_result->bindparam(2, $pwd1); $in_result->bindparam(3, $sex); $in_result->bindparam(4, $age); $in_result->bindparam(5, $email);$in_result->execute(); if($in_result->rowcount()==0) echo 插入记录失败!;else echo 插入记录成功!;//更新 改密码$oldpwd=$_post['oldpwd']; //原密码$newpwd=$_post['newpwd']; //新密码$s_sql=select * from userinfo where username='$username'; //sql语句$s_result=$db->query($s_sql); list($username,$password,$sex,$age,$email)=$s_result->fetch(pdo::fetch_num);if($password!=$oldpwd) //判断原密码是否正确 echo 原密码错误!;else { $checkpwd=preg_match('/^\w{6,20}$/',$newpwd);if(!$checkpwd) echo 新密码格式不满足要求!;else { $update_sql=update userinfo set password='$newpwd' where username='$username'; $affected=$db->exec($update_sql); if($affected) echo密码修改成功!; else echo 密码修改失败!; }}//删除 注销session_start();$username=@$_session['userid'];$delete_sql=delete from userinfo where username='$username'; //注销自己的sql语句$affected=$db->exec($delete_sql); if($affected) echo 注销用户成功!;else echo 注销用户失败!;
1.6 pdo与jpa闲谈 软件开发框架总是有很多互通的地方,因为无论任何开发语言,java或者php底层实现都离不开数据结构,算法,还有软件设计模式,而这些都是互通的,而好的软件框架离不开设计模式运用.
自从学习php接触了解到pdo对象扩展时我便联想到我曾使用的springboot jpa持久层框架,于是我查了些资料,以下便是我的个人理解:
首先先解释一下pdo和jpa的概念
pdophp 数据对象(php data objects) 扩展为php访问数据库定义了一个轻量级的一致接口。
pdo 提供了一个 数据访问 抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。pdo 不提供 数据库 抽象层;它不会重写 sql,也不会模拟缺失的特性。如果需要的话,应该使用一个成熟的抽象层。
pdo架构概念图
jpa
jpa是java persistence api的简称,中文名java持久层api,是jdk 5.0注解或xml描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
jpa仅仅是一种规范,也就是说jpa仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,而hibernate就是实现了jpa接口的orm框架。
jpa 概念关系图
从上述概念和架构图可以看出pdo和jpa还是有一定区别的。首先php的pdo只是一个抽象的数据访问接口层,它对数据库的访问还要依赖相应的数据库驱动,而且需要自行编写操作数据的sql语句。
而java的jpa则是一个持久层规范,也就是说jpa仅仅定义了一些接口,这些接口是关于类和数据库表的映射的,也就是说,jpa这个规范在数据访问接口层之上,而真正实现这个规范和底层数据访问接口是在如hibernate的这些数据持久层框架内.
以hibernate这个持久层框架为例,它实现了对象和数据库表的映射关系,仅需要操作相应的访问dao层接口即可实现数据库的查询并转换为java对象内部属性数据。而hibernate底层对数据库的访问还得依赖jdbc接口。
由此可见pdo和jpa规范完全处于两个不同层次,jpa是数据访问方法底层的高层次抽象,而pdo仅相当于java的jdbc接口层。pdo的抽象层次相对较低,这也符合php的轻量级web开发语言
的特点,这也是它的一个优点,可以方便清晰地实现一些复杂的数据库访问操作,但不利于复杂的高抽象度的大型项目的开发.
以上内容为个人对php pdo对象和java jpa规范的一些理解和比较,水平有限,可能会有不准确的地方。
1.7 实验问题与总结1.7.1 mysql连接php使用mysql原生密码连接如
$conn=mysqli_connect('localhost','user','123456')or die('连接失败');
会出现错误:the server requested authentication method unknown to the client.
原因:
由于本地使用mysql版本在8.0以上,而mysql 8升级了密码的验证方式 caching_sha2_password,所以原生连接会失败,解决办法使用sql修改用户登录验证方式:
use mysql;alter user 'root'@'localhost' identified with mysql_native_password by '你的密码';
1.7.2 sql注入总结php使用mysqli或pdo的query方法查询时,如未对用户表单输入数据进行处理可能会存在sql注入隐患,如
$username=$_post['username'];$password=$_post['password']; //magic_quotes_gpc设为off的情况下//mysql$conn = mysqli_connect(localhost, user ,123456) or die('连接失败'); //mysql_connect()链接mysql服务器mysqli_select_db($conn,'pxscj') or die('选择数据库失败'); //mysql_select_db()选择数据库mysqli_query($conn,set names utf-8);//设置字符集为utf-8$str=select * from userinfo where username='$username' and password='$password';$result=mysqli_query($conn,$str); //pdo//连接数据库,新建pdo对象$pdo=new pdo(mysql:host=localhost;dbname=pxscj,user,123456);$str=select * from userinfo where username='$username' and password='$password';$result=$pdo->query($str);
当用户输入username值为user,password值为123 ' or 1=1,即查询sql被转义为:
select * from userinfo where username='user' and password='123 ' or ' 1=1'
则用户将跳过密码的查询验证得到所有userinfo的数据,并且还存在其他sql语句越权执行的风险
处理风险的方法有以下几种:
addslashes()函数转义$password=addslashes($password);
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。预定义字符是:
单引号(')
双引号()
反斜杠(\)
null
使用pdo对象的prepare()方法$sql=select * from userinfo where username='$username' and password='$password';//注意不是中文状态下的问号? $result=$pdo->prepare($sql); //按照?的顺序绑定参数值 $result->bindparam(1,$username); $result->bindparam(2,$password); $result->execute();
大家如果感兴趣的话,可以点击《php视频教程》进行更多关于php知识的学习。
以上就是php中值得收藏的pdo对象安装配置与使用的详细内容。