![PHP从入门到精通(微视频精编版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/433/34752433/b_34752433.jpg)
第10章 PDO数据库抽象层
(视频讲解:45分钟)
在PHP的早期版本中,各种不同的数据库扩展(MySQL、MS SQL、Oracle)根本没有真正的一致性,虽然都可以实现相同的功能,但是这些扩展却互不兼容,都有各自的操作函数,各自为政。结果导致PHP的维护非常困难,可移植性也非常差,为了解决这些问题,PHP的开发人员编写了一种轻型、便利的API来统一各种数据库的共性,从而达到PHP脚本最大程度的抽象性和兼容性,这就是数据库抽象层。而在本章中将要介绍的是目前PHP抽象层中最为流行的一种——PDO数据库抽象层。
学习摘要:
PDO概述
使用PDO连接数据库
PDO中执行SQL语句
PDO中获取结果集
捕获异常
10.1 什么是PDO
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P202_1.jpg?sign=1739262713-lYLUY3ApCya5j1j8Aqor9DlleEg4fLbG-0-a6aa05e91ace8ae6eb7ffae3c806d88f)
视频讲解
10.1.1 PDO概述
PDO是PHP Date Object(PHP数据对象)的简称,它是与PHP 5.1版本一起发行的,目前支持的数据库包括Firebird、FreeTDS、Interbase、MySQL、MS SQL Server、ODBC、Oracle、PostgreSQL、SQLite和Sybase。有了PDO,不必再使用mysql_*函数、oci_*函数或者mssql_*函数,也不必再为它们封装数据库操作类,只需要使用PDO接口中的方法就可以对数据库进行操作。在选择不同的数据库时,只需修改PDO的DSN(数据源名称)即可。
注意
从PHP 5.1开始附带了PDO,PDO需要PHP 5核心的新面向对象特性,因此不能在较早版本的PHP上运行。
10.1.2 PDO特点
PDO是一个“数据库访问抽象层”,作用是统一各种数据库的访问接口,与MySQL函数库相比,PDO让跨数据库的使用更具有亲和力;与ADODB和MDB2相比,PDO更高效。此外,PDO还具有以下特点:
PDO将通过一种轻型、清晰、方便的函数,统一各种不同RDBMS库的共有特性,实现PHP脚本最大程度的抽象性和兼容性。
PDO吸取现有数据库扩展成功和失败的经验教训,利用PHP 5的最新特性,可以轻松地与各种数据库进行交互。
PDO扩展是模块化的,能够在运行时为数据库后端加载驱动程序,而不必重新编译或重新安装整个PHP程序。例如,PDO_MySQL扩展会替代PDO扩展,实现MySQL数据库API。还有一些用于Oracle、PostgreSQL、ODBC和Firebird的驱动程序。
10.1.3 安装PDO
默认情况下,PDO在PHP 7中为开启状态,但是要启用对某个数据库驱动程序的支持,仍需要进行相应的配置操作。
在Windows环境下,PDO在php.ini文件中进行配置,如图10.1所示。
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P203_1.jpg?sign=1739262713-YKUsKOV0mgpCnb9et7d5E9Hlf35IuxsZ-0-a5c917691e4731521ccbd358a68044c5)
图10.1 Windows环境下配置PDO
要启用PDO,首先必须加载extension=php_pdo.dll,如果要想其支持某个具体的数据库,那么还要加载对应的数据库选项。例如,要支持MySQL数据库,则需要加载extension=php_pdo_mysql.dll选项。
注意
在完成数据库的加载后,要保存php.ini文件,并且重新启动Apache服务器,修改才能够生效。
10.2 PDO连接数据库
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P203_2.jpg?sign=1739262713-grlgNd9LYU9Bn0TGK8n8N61BA1Y4LuY9-0-1f3078bd643e9d32506657460d17de39)
视频讲解
10.2.1 PDO构造函数
在PDO中,要建立与数据库的连接需要实例化PDO的构造函数,PDO构造函数的语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P203_3.jpg?sign=1739262713-vK5UPYJeIr2AKj0VG02qlXBkfXAjpP2M-0-b75c1d06beb1a952b8ae114e5083d76b)
参数说明如下。
dsn:数据源名,包括主机名、端口号和数据库名称。
username:连接数据库的用户名。
password:连接数据库的密码。
driver_options:连接数据库的其他选项。
通过PDO连接MySQL数据库的代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P203_4.jpg?sign=1739262713-T2HTmdTmGA3lKEXI43uWSyAAhMGPbSxe-0-f4366166d6fddb1ff675338effe1aa2e)
10.2.2 DSN详解
DSN是Data Source Name(数据源名称)的首字母缩写。DSN提供连接数据库需要的信息。PDO的DSN包括3部分:PDO驱动名称(如mysql、sqlite或者pgsql)、冒号和驱动特定的语法。每种数据库都有其特定的驱动语法。
数据库服务器是完全独立于PHP的实体。数据库服务器可能与Web服务器不是在同一台计算机上,此时要通过PDO连接数据库时,就需要修改DSN中的主机名称。
每种数据库服务器都有一个默认的端口号(MySQL默认是3306),数据库管理员可以对端口号进行修改,因此有可能PHP找不到数据库的端口,此时就需要在DSN中包含端口号。
另外由于一个数据库服务器中可能拥有多个数据库,所以在通过DSN连接数据库时,通常都包括数据库名称,这样可以确保连接的是想要的数据库,而不是其他的数据库。
10.3 PDO中执行SQL语句
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P204_2.jpg?sign=1739262713-QTB3YFTGAR64fdDk55yBQyHR8otZPdwJ-0-c7e610fcc1ce78a6579f83fde166f82a)
视频讲解
在PDO中,可以使用下面的3种方法来执行SQL语句。
1.exec()方法
exec()方法返回执行后受影响的行数,其语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P204_3.jpg?sign=1739262713-6wL3pPdXvHqSX93luR62Ioc8jr2lHV2o-0-1ae44eba1027473f1917be59020e72c7)
参数$statement是要执行的SQL语句。该方法返回执行查询时受影响的行数,通常用于insert、delete和update语句中。
例如,使用exec()执行删除操作,删除member表中id为1的记录。代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P204_4.jpg?sign=1739262713-cDrWC0rbgigwMsBWt9aTuQmz3hCx9h5c-0-9df5d9b402950443bf970447715059a1)
2.query()方法
query()方法用于返回执行查询后的结果集。其语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P205_2.jpg?sign=1739262713-dgJSD2pmERy3UJ8XGDdYikXE2WK7TkWW-0-57822f15ad96f1b6a7f50e07a056ac36)
其中参数$statement是要执行的SQL语句。它返回的是一个PDOStatement对象。
例如,使用query()执行查询操作,查询member表中所有记录的id。代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P205_3.jpg?sign=1739262713-mN7hcu7erg9Ye71qOBYxzFzJxW4lJnEK-0-919d3f6ddf07c9e91ddcf23e9a28cfeb)
3.预处理语句——prepare()和execute()
预处理语句包括prepare()和execute()两个方法。首先,通过prepare()方法做查询的准备工作,语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P205_4.jpg?sign=1739262713-p7SqJA1v60x0rGQ6V1BKt1FCw71C71iK-0-dfaa0636788b2383af80dc872fac0775)
其中参数$statement是要执行的SQL语句。它返回的是一个PDOStatement对象。
然后,通过execute()方法执行查询,并且还可以通过bindParam()方法来绑定参数提供给execute()方法。其语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P205_5.jpg?sign=1739262713-jGp2ibiXR1aItC2JqeMW7KX4dLnfhiUd-0-ab874e8305e613803786f86f4a34402e)
例如,查询member表中id大于2且会员等级为C的所有记录。代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P205_6.jpg?sign=1739262713-mA1KlYYIPP7Erjl704oW62EKaUZSEQLT-0-73de498aaedac48b35724f29d9864f25)
10.4 PDO中获取结果集
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P206_1.jpg?sign=1739262713-0Wjwx80VoPDOPS0wvT0jDJXtQBsk5ul4-0-05676e3092d5b946f0fd2c849afce013)
视频讲解
在PDO中获取结果集常用3种方法:fetch()、fetchAll()和fetchColumn()。
10.4.1 fetch()方法
fetch()方法可以获取结果集中的下一行记录,其语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P206_2.jpg?sign=1739262713-oDOVRdb1LiWTgR6ymCtxTSW88oHjuuor-0-a373c4a495e76afff6ef5a4ffce930ec)
参数说明如下。
fetch_style:控制结果集的返回方式,其可选方式如表10.1所示。
表10.1 fetch_style控制结果集的可选值
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-T206_3.jpg?sign=1739262713-PPpuBrRPfPZiYJa1En3sM4dvyQV3X1a2-0-5b0c6933f7582ffff8f1d0b5dc00b5fc)
cursor_orientation:PDOStatement对象的一个滚动游标,可用于获取指定的一行。
cursor_offset:游标的偏移量。
【例10.01】 使用fetch()方法获取明日学院会员列表。(实例位置:资源包\源码\10\10.01)
通过fetch()方法获取结果集中下一行的数据,进而应用while语句完成数据库中数据的循环输出,具体步骤如下。
(1)创建member表。首先创建database10数据库,并设置数据库编码格式为UTF-8。创建member表的SQL语句如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P206_4.jpg?sign=1739262713-93Z9bPo1w5pmzaGicxUtfm2vZEBqljMs-0-d8f97021e8b9f81af26302243b6053eb)
(2)插入测试数据。为了显示会员信息,我们需要先在member表中插入几条测试数据。插入数据的SQL语句如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P207_2.jpg?sign=1739262713-G9iPLzd9a5BEl3sPXzrx9im8XBe3EJnI-0-67f7ed8c7cae5547939e9b1a78c159a6)
(3)创建数据库配置文件config.php,代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P207_3.jpg?sign=1739262713-UggYSzpkaYIM9uOuZ8ygGpiNPqN7KJvr-0-610dd96d24d0345d0254a2ee3ec60cd8)
(4)创建index.php文件,用于连接数据库,执行查询语句,并引入模板文件。index.php文件的具体代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P207_4.jpg?sign=1739262713-7lX5DdnqN7hiurFvYLKQoe5VvZoTqjoK-0-dfb0f831b759f96c39374ec325460c24)
(5)创建lists.html文件,显示会员信息。使用$result->fetch(PDO::FETCH_ASSOC)将结果集返回到数组中,通过while语句循环遍历数组,将各会员的数据插入到<table>表格中,具体代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P207_5.jpg?sign=1739262713-h3h7U7aNZjG90QNXVLmbE0UcZ9Cti79W-0-6afff1500d24c0af421c6b3b635c26a3)
使用浏览器访问index.php,运行结果如图10.2所示。
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P209_2.jpg?sign=1739262713-kGQ0eZ7DZyDyTXuVDWH6YfoeuvKXUQMF-0-fc78ee07b5260664db591a3415baa761)
图10.2 显示会员列表
10.4.2 fetchAll()方法
fetchAll()方法可以获取结果集中的所有行。其语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P209_3.jpg?sign=1739262713-tm3XaFPPNDlvxQewyvNmOZ5LRcxwwj0J-0-4ce8bec8acfa2341c36fc662ed08cb1e)
参数及返回值说明如下。
fetch_style:控制结果集中数据的显示方式。
column_index:字段的索引。
返回值:是一个包含结果集中所有数据的二维数组。
【例10.02】 使用fetchAll()方法获取明日学院会员列表。(实例位置:资源包\源码\10\10.02)
通过fetchAll()方法获取结果集中所有行,并且通过foreach语句读取二维数组中的数据,完成数据库中数据的循环输出。由于开发流程与例10.01相似,这里只介绍修改的关键代码。
(1)创建index.php文件,用于连接数据库,执行查询语句,并引入模板文件。使用fetchAll(PDO::FETCH_ASSOC)方法获取结果集中所有行,将结果赋值给$data数组。index.php文件修改后代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P209_4.jpg?sign=1739262713-ZHQTYJOBjnehk4BAfSCVZxnwgijjJK6k-0-ec0f35ce03f7b3a345882d3861dcf44d)
(2)创建lists.html文件。使用foreach语句遍历$data数组,将相应数据写入<table>表格,关键代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P210_2.jpg?sign=1739262713-rccdmhi3AJvAos00POG92Pt10iiDDPAv-0-ef46bcd367b2226402840518eed60c71)
运行结果与例10.01相同。
10.4.3 fetchColumn()方法
fetchColumn()方法可以获取结果集中下一行指定列的值。其语法格式如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P210_3.jpg?sign=1739262713-cLset3nf8uscjvzEH2k4dPcTGuApkF38-0-6d3240f1695e80d57a6979ae74dda476)
其中可选参数column_number设置行中列的索引值,该值从0开始。如果省略该参数则从第1列开始取值。
【例10.03】 使用fetchColumn()方法读取会员名。(实例位置:资源包\源码\10\10.03)
通过fetchColumn()方法获取结果集中下一行中指定列的值,注意这里是“指定列的值”。本实例输出member表中nickname的值。具体步骤如下。
(1)创建index.php文件,用于连接数据库,执行查询语句,并引入模板文件。index.php文件的具体代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P211_1.jpg?sign=1739262713-y7LslIO6jGwlQpjCeEpHa300S69kQPME-0-2d63bb341f5240a500a5e1994f7de8d8)
(2)创建lists.html文件,使用fetchColumn()方法获取nickname。关键代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P211_2.jpg?sign=1739262713-phadSNHcuDGkDJL1e9Kz01sykdPOa9Ec-0-ce0e6db2958c56b306a918ac4869710c)
运行结果如图10.3所示。
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P212_1.jpg?sign=1739262713-trn9j1FVqDdLdKbsreOLZZ1cFKS86gYU-0-c211a049c1df78338a925210b8b78fff)
图10.3 fetchColumn()方法获取用户昵称
10.5 PDO中捕获SQL语句中的错误
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P212_2.jpg?sign=1739262713-v3yNyqgTTlmpXmfRwyohAoTQ6POe7QWk-0-8484c72a154ea4d071b4595ff56a03b8)
视频讲解
在PDO中有3种方法可以捕获SQL语句中的错误,分别为:默认模式(PDO::ERRMODE_SILENT)、警告模式(PDO::ERRMODE_WARNING)和异常模式(PDO::ERRMODE_EXCEPTION)。下面就对这3种方法分别进行讲解。
10.5.1 默认模式
在默认模式中设置PDOStatement对象的errorCode属性,但不进行其他任何操作。
通过prepare()和execute()方法向数据库中添加数据,设置PDOStatement对象的errorCode属性,手动检测代码中的错误。
【例10.04】 使用默认模式捕获SQL语句中的错误。(实例位置:资源包\源码\10\10.04)
创建index.php文件。通过PDO连接MySQL数据库,通过预处理语句prepare()和execute()执行insert添加语句,向数据表中添加数据,并且设置PDOStatement对象的errorCode属性,检测代码中的错误。代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P212_3.jpg?sign=1739262713-1jJpeaSZNDS9QYuyZbOd5k2KSJshVsWm-0-4cf1e35531047143e87f33de6eb74ecb)
在本实例中,在定义insert添加语句时,使用了错误的数据表名称members(正确名称是member),导致输出结果如图10.4所示。
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P213_2.jpg?sign=1739262713-bbWU5OscR6lOWyolqHFznLPIizrJwerM-0-753c2850b38d2ba58722fb7e137be3e4)
图10.4 在默认模式中捕获SQL中的错误
10.5.2 警告模式
警告模式会产生一个PHP警告,并设置errorCode属性。如果设置的是警告模式,那么除非明确地检查错误代码,否则程序将继续按照其方式运行。
例如,设置警告模式,通过prepare()和execute()方法读取数据库中数据,体会在设置成警告模式后执行错误的SQL语句。具体代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P213_3.jpg?sign=1739262713-bQnGV3NVS5D6ACZ7fkhsJYKgn9DJ8gQ6-0-4d62af8db1924044517bec5277e36b17)
在设置为警告模式后,如果SQL语句出现错误将给出一个提示信息,但是程序仍能够继续执行下去,其运行结果如图10.5所示。
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P214_2.jpg?sign=1739262713-yqbiw8gES10ZUgodEeovsNKwvSHT4slh-0-e75544f8eba4bb4a39bf33876e0103a0)
图10.5 设置警告模式后捕获的SQL语句错误
10.5.3 异常模式
异常模式会创建一个PDOException,并设置errorCode属性。它可以将执行代码封装到一个try{…}catch{…}语句块中。未捕获的异常将会导致脚本中断,并显示堆栈跟踪,让我们了解是哪里出现的问题。
例如,在执行数据库中数据的删除操作时,设置为异常模式,并且编写一个错误的SQL语句(操作错误的数据表members),体会异常模式与警告模式和默认模式的区别。具体代码如下:
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P214_3.jpg?sign=1739262713-f2yeXw4acBjde2MYuBJaoh8YCseW4Ihd-0-1a023151c3015f0d2422c5f647a2f0ed)
在设置为异常模式后,执行错误的SQL语句返回的结果如图10.6所示。
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P215_1.jpg?sign=1739262713-HxRZ6C7OfyDOVtsPUA40XffkP8yDrjoI-0-9f13d01e02d4aae3fa1a1e9946f9e83e)
图10.6 异常模式捕获的SQL语句错误信息
10.6 小结
本章重点介绍了数据库抽象层——PDO,从它的概述、特点和安装开始讲解,到它的实际应用,包括如何连接不同的数据库、如何执行SQL语句、如何获取结果集,以及错误处理,再到它的高级应用事务都进行了详细讲解,并且都配有相应的实例。通过本章的学习,相信读者能够掌握PDO技术的应用。
10.7 实战
10.7.1 获取所有会员的“邮箱”信息
实例位置:资源包\源码\10\实战\01
试着修改例10.03,使用fetchColumn()方法获取所有会员的“邮箱”信息。
10.7.2 使用默认模式捕获SQL语句中的错误
实例位置:资源包\源码\10\实战\02
试着删除例10.04中config.php文件中的数据库密码,使用默认模式捕获SQL语句中的错误,如图10.7所示。
![](https://epubservercos.yuewen.com/3D7998/18562448408358606/epubprivate/OEBPS/Images/Figure-P215_2.jpg?sign=1739262713-KJzsDl4dEToLB4nTAxAbcU3RvXoFqM36-0-48bb3326fa65d739f17d093738ce206f)
图10.7 捕获异常