《PHP精粹:编写高效PHP代码》——2.4节PHP数据库对象

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介:

本节书摘来自华章社区《PHP精粹:编写高效PHP代码》一书中的第2章,第2.4节PHP数据库对象,作者:(美)  Davey Shafik,更多章节内容可以访问云栖社区“华章社区”公众号查看

2.4 PHP数据库对象
如果之前你使用过PHP和MySQL,你可能用过mysql或mysqli类库连接到数据库,如使用mysql_connect()函数。多年来,这是连接到MySQL数据库的标准方式,并且对于其他数据库平台也使用同样的方式。
这些类库可以直接使用,并形成了无数PHP应用程序类库和框架的基础。这种方式的缺点是每个扩展都与其他稍有不同,因此使得代码在数据库平台之间轻松转移变得复杂。虽然这些数据库特定类库依然活跃并且运转良好,但是本章中仍将专注讲解更先进的PDO扩展。创建的PDO扩展提供了一组统一功能与各种数据库平台的对话。PHP 5采用的就是面向对象的扩展,当时人们将它的很多特性引入了PHP语言。
理解OOP
如果你不熟悉面向对象编码,并且已仔细阅读第1章,现在你正好可以了解使用OOP的更多内容。

然而,PDO并没有解决问题,这个问题是出现在不同数据库平台之间的SQL语法差异;因此,乍看起来似乎这个扩展并不完全是最有效的手段。PDO可以和各种各样的数据库平台连接和对话,但是为了创建真正独立于平台的应用程序,我们不得不改写发送的SQL语句。
PDO是一个抽象层,这表明它建立在PHP以及PHP连接数据库的方式之间。PDO提供了非常简洁的功能来执行查询和遍历数据集,让我们深入研究如何使用PDO的技术细节吧。

2.4.1 使用PDO连接到MySQL
要使用PDO连接到数据库,需要实例化一个新的PDO对象并且传递一个DSN,如果需要,还要加上用户名和密码。DSN(Data Source Name, 数据源名称)由描述实际连接的数据结构组成。若要连接到创建(数据库名称recipes,使用localhost作为主机名)的数据库,将使用下面的PHP代码生成连接:


cd1e84ba87c13097ef5f46e537e2739a9d6eddf3


06afb1a219b17dd39bdf2b32ac9ba661ec446896

2.4.2 从表中选择数据
创建了PDO对象之后,就可以检索数据了。首先,在数据库中会有怎样的食谱清单呢?当用PDO选择数据时,要创建一个PDOStatement对象。它代表查询,并使我们获取结果。对于一个基本的查询,可以使用PDO::query()方法:


0cb7af03a94aa710b1490144e862def472b8b4b3

使用ORDER对结果排序
当我们像这样从MySQL中选择数据时,将得到以未定义的顺序返回的记录;通常这些记录是按照插入的顺序排序的。为成为更完美的应用,可以在查询的末尾添加这样的命令:ORDER BY created DESC。将按时间的降序返回结果,即总是先看到最新的食谱。

以上示例利用了PDOStatement::fetch()方法,此方法能处理大量提取数据的模式。
2.4.3 数据提取模式
在前面的示例中,我们看到了如何用PDOStatement对象来表示查询及其数据集。每次调用fetch()方法,都将从结果集中接收到另外一行。还可以使用fetchAll()方法一次检索所有的行。这两种方法都接受fetch_style参数,这个参数定义如何格式化结果集。
PDO提供了便于使用的常量:
PDO::FETCH_ASSOC完成了以前你在while循环中看到的,它使用键组返回数组到列名。
PDO::FETCH_NUM也返回数组,但这次使用数字键。
PDO::FETCH_BOTH(默认值)结合了PDO::FETCH_ASSOC和PDO::FETCH_NUM以提供一个每个值出现两次的数组,一次使用其列名,一次使用数字索引。
PDO::FETCH_CLASS返回一个已命名的类的对象而不是数组,这些值以列的名字命名设置到属性中。
为了看到由PDO::FETCH_ASSOC返回的结果,可以输入下列代码:


c6597b482d27a214775c2035eec9750cd0380292

这里有一些正在运行,让我们依次看看它们。
首先,通过传递SQL语句进入prepare()方法创建了PDOStatement。仔细观察这条SQL语句,你可能会看到一些奇怪的东西。在:recipe_id前面的冒号表示这是一个占位符(placeholder)。在实际运行这个查询之前,会用真正的值来替换这个占位符。
然后,execute()这个查询。必须为字符串中的每个占位符传入值,而且还要将这些字符串传入prepare()方法中。因为使用指定的占位符,所以要创建一个由与这些占位符数量相同的元素组成的数组。每个占位符都有一个与之匹配的数组元素,数组元素的名字作为键值,然后要用它的实际值来替换键值。
既然已知道只能返回一行,可以通过调用一次fetch()方法来代替循环。

生成SQL语句
在之前的示例中,定义了一个单独的$sql变量来保存这个字符串并传入PDO::prepare。这种方法可以让代码更易于阅读,并且在需要建立一个更复杂的查询时提供帮助。这种方式也可以帮助我们进行调试,你可以不费力地检查有哪些东西传入了prepare()。

占位符不需要名字,你也可以使用??符号为变量保留一个位置作为没有命名的占位符。此外,在SQL语句中有很多这样的占位符,用它们来创建PDOStatement,而且作为数组把这些值传入execute()中,但在这个例子中,我们必须将这些值按顺序排列在查询语句中。用下面的示例很容易说明这些:
如果查询变得很庞大或很复杂,命名占位符可使你更容易保存代码。将数组中命名的键值传入execute(),比起应付一个巨大的用数字作为索引的数组,这种方式让你更容易看出哪个值属于哪个参数。
预处理语句使我们清楚地标识出查询中哪些部分是数据库语言,哪些包含可变数据。你会听说“安全咒语”:“过滤输入,避免输出”(如果你还未听说,在第5章将很快看到)。当使用数据库时,必须溢出已经发送到数据库的值(也就是说删除不需要的字符)。你可能见过像mysql_escape_string()这样的MySQL功能。当使用预处理语句时,为占位符传入的值已经溢出,因为MySQL知道这些都是可能改变的值。这种额外的安全保障是将PDO及预处理语句作为规范令人信服的一个原因。

2.4.5 绑定值和预处理语句的变量
既然MySQL已经准备了一个查询,那么使用不同的值再次运行这个查询时只会有很小的系统开销。我们已经知道了如何传递变量到PDOStatement的execute()方法中。在本节中,我们将看到如何绑定值甚至变量到语句中,以便在每次执行查询时都使用这些值或变量。
解释概念的简单例子
这些例子可能看起来确实没有什么意义,但举例说明数据集里更多先进的技术的确是种乐趣!如果你问自己:“为什么我要尝试这些呢?”要记住这些都是适用于你自己项目的技术(可能用在更复杂的设置中)。

虽然这是事实,但总的来说,我们最好用尽可能少的步骤从数据库中检索数据,有时你使用的查询类型意味着这些步骤不能组合使用。当使用不同的值重复调用相同的查询时,可以设置一些元素用于每次查询。
例如,如果我们总想使用同样的chef值,可以使用PDOStatement::bindValue():


85fa0a699aa42fd388ff4f2a007be74ad1526ffa

最后这两个例子表明了在调用execute()方法之前如何设定值或变量到PDOStatement对象。不管你是使用bindValue()方法、bindParam()方法或是传入值到execute()方法本身,预处理语句都是极为有用的!如果我们多次运行这个语句,这种方式不仅能够提高代码的性能,而且也可以毫无疑问地溢出占位符。

2.4.6 插入一行并获取ID
前面已经深入研究了SELECT语句的选项,但是INSERT和UPDATE语句又怎么样呢?实际上这几个语句看起来确实很相似,即我们预处理然后再执行一条语句。接下来以插入一些新的食谱作为示例:


7c8794c3aeaa38d16f9c67befd3b09897e394459

rowCount()是PDOStatement对象的一个方法,它会指出有多少行由于查询而发生改变。
2.4.8 删除数据
和插入或更新数据一样,我们以相同的方式删除数据,即对查询进行预处理然后再执行查询。如果想删除“Starter”这一类别(因为它未使用),可以这样做:


d59dfc66703bfd83d89be0cdfe5e1917051fa353

我们会再次使用rowCount()方法检查删除行,查看其数量是否和预期的一样多(很多缺失的或错误的WHERE子句比预期会造成更大损害)。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
IDE PHP 开发工具
PHP中的类型提示与严格模式:提高代码可维护性
随着PHP语言的发展,开发者对代码的可读性、可维护性和可靠性有了更高的要求。PHP中的类型提示(Type Hinting)和严格模式(Strict Mode)为开发者提供了更强的类型检查机制,有助于提升代码质量和减少潜在的错误,尤其是在大型项目中。
|
3月前
|
存储 SQL 关系型数据库
PHP与数据库交互:从基础到进阶
【10月更文挑战第9天】在编程的世界里,数据是流动的血液,而数据库则是存储这些珍贵资源的心脏。PHP作为一门流行的服务器端脚本语言,其与数据库的交互能力至关重要。本文将带你从PHP与数据库的基本连接开始,逐步深入到复杂查询的编写和优化,以及如何使用PHP处理数据库结果。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识和技巧,让你在PHP和数据库交互的道路上更加从容不迫。
|
1月前
|
PHP 开发者 容器
PHP命名空间深度解析:避免命名冲突与提升代码组织####
本文深入探讨了PHP中命名空间的概念、用途及最佳实践,揭示其在解决全局命名冲突、提高代码可维护性方面的重要性。通过生动实例和详尽分析,本文将帮助开发者有效利用命名空间来优化大型项目结构,确保代码的清晰与高效。 ####
36 1
|
27天前
|
SQL Java 数据库连接
JDBC编程安装———通过代码操控数据库
本文,教你从0开始学习JBCD,包括驱动包的下载安装调试设置,以及java是如何通过JBDC实现对数据库的操作,以及代码的分析,超级详细
|
2月前
|
供应链 安全 NoSQL
PHP 互斥锁:如何确保代码的线程安全?
在多线程和高并发环境中,确保代码段互斥执行至关重要。本文介绍了 PHP 互斥锁库 `wise-locksmith`,它提供多种锁机制(如文件锁、分布式锁等),有效解决线程安全问题,特别适用于电商平台库存管理等场景。通过 Composer 安装后,开发者可以利用该库确保在高并发下数据的一致性和安全性。
48 6
|
2月前
|
PHP 开发者 UED
探索PHP中的异常处理:提升代码的健壮性
在PHP开发中,优雅地处理错误和异常是确保应用稳定性和用户体验的关键。本文将通过深入浅出的方式,介绍如何在PHP中实现有效的异常处理机制,包括异常的基本概念、如何抛出和捕获异常,以及最佳实践。准备好让你的代码变得更加健壮和可靠吧!
26 2
|
2月前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
80 1
|
2月前
|
JSON JavaScript 关系型数据库
node.js连接GBase 8a 数据库 并进行查询代码示例
node.js连接GBase 8a 数据库 并进行查询代码示例
|
2月前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
2月前
|
PHP 开发者
PHP中的异常处理:提升代码的健壮性
【10月更文挑战第40天】在PHP编程中,异常处理是确保应用稳定性的关键。本文将引导你理解异常处理的重要性,掌握如何在PHP中捕获和处理异常,以及如何通过自定义异常类来增强代码的错误管理能力。我们将一起探索如何利用PHP的异常处理机制,打造一个更加健壮和可靠的应用程序。

热门文章

最新文章