简介

  前面咱已经见过MySQLi了,现在咱一起来看看PDO类。PDO是PHP Data Objects的缩写,它被描述为“在PHP中访问数据库的轻量级,兼容性的接口”。尽管它的名字不咋好听,但PDO是一个在PHP中访问数据库会让人喜爱的方式。

 与MySQLi的不同

  MySQLi和PDO很相似,都有两方面主要区别:

  1.MySQLi只能访问MySQL,但PDO可以访问12种不同的数据库

  2.PDO没有普通函数调用(mysqli_*functions)

 开始步骤

  首先,你得确定一下你的PHP是否安装了PDO插件。你可以用$test=new PDO()的结果来测试。如果提示说是参数不匹配,那证明已经安装了PDO插件,如果说是对象不存在,你得先确认一下在pho.ini中php_pdo_yourssqlserverhere.extis是否被注释掉了。如果没有这句话,那你得安装PDO了,这里就不啰嗦了。

  连接

  现在我们确认服务器已经工作,开始连接数据库吧:

1
2
3
4
5
6
7
8
$dsn = 'mysql:dbname=demo;host=localhost;port=3306';
$username = 'root';
$password = 'password_here';
try {
    $db = new PDO($dsn, $username, $password); // also allows an extra parameter of configuration
} catch(PDOException $e) {
    die('Could not connect to the database:<br/>' . $e);
}

  除$dsn之外,所有语句和变量都能自我解释。DSN指的是数据源名称,有多种输入类型。最常见的一种是我们刚刚用的这种,PHP官网解释了 其他可用的DSN

  你可以省去DSN的其他额外参数,只需要在数据库驱动后面带个冒号,比如(mysql:)。在这种情况下PDO将会尝试连接到本地数据库。就像当你使用MySQLi时需要在查询中指定数据库名称一样。

  最后一件你需要注意的事情就是我们用try-catch块包裹了我们的初始化对象。PDO连接失败的时候将会抛出PDOException异常而不是查询失败的时候。如果你愿意你可以使用下面代码$db=line来选择异常的模式。

1
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  或者你可以直接在PDO初始化时传递参数:

1
2
3
$db = new PDO($dsn, $username, $password, array (
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));

  我们现在使用的是错误的方式——在失败时候简单返回false,我们是没有理由不对异常进行处理的。

 基本查询

  在PDO中使用query和exec两种方法使得对数据库查询变得非常简单。如果你想得到查询结果的行数exec是非常好用的,因此对SELECT查询语句是非常有用的。

  现在我们通过下面的一个例子查看这两种方法:

1
2
3
4
5
6
7
$statement = <<<SQL
    SELECT *
    FROM `foods`
    WHERE `healthy` = 0
SQL;
 
$foods = $db->query($statement);

  假设我们的查询是正确的,$foods现在是一个PDO Statement对象,我们可以用它获取到我们的结果或者是查看这次查询中一共查到多少条结果集。

 行数

  不足的是,PDO没有提供一个统一的方法去计算返回的行数。PDO Statement包含了一个叫做rowCount的方法,但是这个方法却不能保证在每一个SQL驱动中起作用(幸运的是,它能够在Mysql数据库中起作用)。

  如果你的SQL驱动不支持这个方法,你也有2个选择:使用二次查询(SELECT COUNT(*))或者使用简单的count($foods)得到行数。

  幸运的是对我们的MySQL例子,我们可以使用下面的简单方法来输出正确的行数。

1
echo $foods->rowCount();

 遍历结果集

  打印出这些可口的食物一点也不困难:

1
2
3
foreach($foods->FetchAll() as $food) {
    echo $food['name'] . '<br />';
}

  唯一需要注意的是PDO也支持Fetch方法,这个方法只会返回第一条结果,这对于只需要查询一条结果集是非常有用的。

 转义用户输入(的特殊字符)

  你可曾听说过(mysqli_)real_escape_string,这是用于确保用户输入安全数据。PDO提供了一个方法叫做quote,这个方法可以把输入字符串中带有引号的地方进行特殊字符转义。

1
$input: this is's' a '''pretty dange'rous str'ing

  在转义后,最终得到下面结果:

1
$db->quote($input): 'this is\'s\' a \'\'\'pretty dange\'rous str\'ing'

 exec()

  正如上面提到的,你可以使用exec()方法实现UPDATE,DELETE和INSERT 操作,执行后它会返回受影响行数的数量:

1
2
3
4
5
6
$statement = <<<SQL
    DELETE FROM `foods`
    WHERE `healthy` = 1;
SQL;
 
echo $db->exec($statement); // outputs number of deleted rows

 预处理语句

  尽管exec方法和查询在PHP中仍然被大量使用和支持,但是PHP官网上还是要求大家用预处理语句的方式来替代。为什么呢?主要是因为:它更安全。预处理语句不会直接在实际查询中插入参数,这就避免了许多潜在的SQL注入。

  然而出于某种原因,PDO实际上并没有真正的使用预处理,它是在模拟预处理方式,在将语句传给SQL服务器之前会把参数数据插入到语句中,这使得某些系统容易受到SQL注入。

  如果你的SQL服务器不真正的支持预处理,我们可以很容易的通过如下方式在PDO初始化时传参来修复这个问题:

1
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

  接下来开始我们的第一个预处理语句吧:

1
2
$statement = $db->prepare('SELECT * FROM foods WHERE `name`=? AND `healthy`=?');
$statement2 = $db->prepare('SELECT * FROM foods WHERE `name`=:name AND `healthy`=:healthy)';

  正如你所见,有两种创建参数的方法,命名的与匿名的(不可以同时出现在一个语句中)。然后你可以使用bindValue来敲进你的输入:

1
2
3
4
5
$statement->bindValue(1, 'Cake');
$statement->bindValue(2, true);
 
$statement2->bindValue(':name', 'Pie');
$statement2->bindValue(':healthy', false);

  注意使用命名参数的时候你要包含进冒号(:)。PDO还有一个bindParam方法,可以通过引用绑定数值,也就是说它只在语句执行的时候查找相应数值。

  现在剩下的唯一要做的事情,就是执行我们的语句:

1
2
3
4
5
6
$statement->execute();
$statement2->execute();
 
// Get our results:
$cake = $statement->Fetch();
$pie  = $statement2->Fetch();

  为了避免只使用bindValue带来的代码碎片,你可以用数组给execute方法作为参数,像这样:

1
2
$statement->execute(array(1 => 'Cake', 2 => true));
$statement2->execute(array(':name' => 'Pie', ':healthy' => false));

 事务

  前面我们已经描述过了什么是事务:

  一个事务就是执行一组查询,但是并不保存他们的影响到数据库中。这样做的好处是如果你执行了4条相互依赖的插入语句,当有一条失败后,你可以回滚使得其他的数据不能够插入到数据库中,确保相互依赖的字段能够正确的插入。你需要确保你使用的数据库引擎支持事务。

 开启事务

  你可以很简单的使用beginTransaction()方法开启一个事务:

1
2
3
$db->beginTransaction();
 
$db->inTransaction(); // true!

  然后你可以继续执行你的数据库操作语句,在最后提交事务:

1
$db->commit();

  还有类似MySQLi中的rollBack()方法,但是它并不是回滚所有的类型(例如在MySQL中使用DROP TABLE),这个方法并不是真正的可靠,我建议尽量避免依赖此方法。

 其他有用的选项

  有几个选项你可以考虑用一下。这些可以作为你的对象初始化时候的第四个参数输入。

1
2
$options = array($option1 => $value1, $option[..]);
$db = new PDO($dsn, $username, $password, $options);

  PDO::ATTR_DEFAULT_FETCH_MODE

  你可以选择PDO将返回的是什么类型的结果集,如PDO::FETCH_ASSOC,会允许你使用$result['column_name'],或者PDO::FETCH_OBJ,会返回一个匿名对象,以便你使用$result->column_name

  你还可以将结果放入一个特定的类(模型),可以通过给每一个单独的查询设置一个读取模式,就像这样:

1
2
$query = $db->query('SELECT * FROM `foods`');
$foods = $query->fetchAll(PDO::FETCH_CLASS, 'Food');

所有读取模式

  PDO::ATTR_ERRMODE

  上面我们已经解释过这一条了,但喜欢TryCatch的人需要用到:PDO::ERRMODE_EXCEPTION。如果不论什么原因你想抛出PHP警告,就使用PDO::ERRMODE_WARNING。

  PDO::ATTR_TIMEOUT

  当你为载入时间而着急时,你可以使用此属性来为你的查询指定一个超时时间,单位是秒. 注意,如果超过你设置的时间,缺省会抛出E_WARNING异常, 除非 PDO::ATTR_ERRMODE 被改变.

  更多属性信息可以在 PHP官网的属性设置 里查看到.

 最后的思考

  PDO是一个在PHP中访问你的数据库的很棒的方式,可以认为是最好的方式。除非你拒绝使用面向对象的方法或是太习惯 MySQLi 的方法名称,否则没有理由不使用PDO。

  更好的是完全切换到只使用预处理语句,这最终将使你的生活更轻松!

  英文来源:http://codular.com/php-pdo-how-to

PDO 指南的更多相关文章

  1. PHP pdao用法总结

    $sql = 'SELECT name, colour, calories     FROM fruit     WHERE calories < :calories AND colour =  ...

  2. [置顶] PHP开发实战权威指南-读书总结

    从今年开始,断断续续学习PHP已经有4个月了. 最初,认真学习PHP几天,就弄WordPress搭建了一个个人博客,这也符合技术人的实践理念. 最近,重温PHP开发实战权威指南,做点总结,整理下自己学 ...

  3. PHP开发实战权威指南-读书总结

    从今年开始,断断续续学习PHP已经有4个月了.最初,认真学习PHP几天,就弄WordPress搭建了一个个人博客,这也符合技术人的实践理念. 最近,重温PHP开发实战权威指南,做点总结,整理下自己学习 ...

  4. Phalcon如何切换数据库《Phalcon入坑指南系列 三》

    本系列目录 一.Phalcon在Windows上安装 <Phalcon入坑指南系列 一> 二.Phalcon入坑必须知道的功能(项目配置.控制器.模型.增.删.改.查) 三.Phalcon ...

  5. Phalcon多模块如何实现连接不同数据库 《Phalcon入坑指南系列 五》

    本系列目录 一.Phalcon在Windows上安装 <Phalcon入坑指南系列 一> 二.Phalcon入坑必须知道的功能<Phalcon入坑指南系列 二> 三.Phalc ...

  6. JavaScript权威指南 - 函数

    函数本身就是一段JavaScript代码,定义一次但可能被调用任意次.如果函数挂载在一个对象上,作为对象的一个属性,通常这种函数被称作对象的方法.用于初始化一个新创建的对象的函数被称作构造函数. 相对 ...

  7. UE4新手之编程指南

    虚幻引擎4为程序员提供了两套工具集,可共同使用来加速开发的工作流程. 新的游戏类.Slate和Canvas用户接口元素以及编辑器功能可以使用C++语言来编写,并且在使用Visual Studio 或 ...

  8. JavaScript权威指南 - 对象

    JavaScript对象可以看作是属性的无序集合,每个属性就是一个键值对,可增可删. JavaScript中的所有事物都是对象:字符串.数字.数组.日期,等等. JavaScript对象除了可以保持自 ...

  9. JavaScript权威指南 - 数组

    JavaScript数组是一种特殊类型的对象. JavaScript数组元素可以为任意类型,最大容纳232-1个元素. JavaScript数组是动态的,有新元素添加时,自动更新length属性. J ...

随机推荐

  1. PDF文件的加载及展示

    项目需要显示PDF文件,于是遍寻了网络,发现的方法以下几种: 1.使用UIWebView加载,没啥说的,根据文件路径,网络或者本地皆可,创建一个NSURLRequest,然后用webView加载就可以 ...

  2. Android——Activity和Intent及Activity的生命周期

    实验Activity的生命周期 package com.example.chenshuai.test; import android.app.Activity; import android.os.B ...

  3. rsync+inotify-tools

    源服务器:192.168.0.100   目标服务器:192.168.0.101   目的:把源服务器上/home/test目录实时同步到目标服务器的/home/test下   具体操作:   第一部 ...

  4. 谷歌字体(Google Font)初探 [翻译自Google官方文档]

    这个指南解释了如何使用Google Font的API,把网络字体添加到自己的页面上.你不需要任何的编码,你所要做的只是添加一个特定的CSS到HTML页面上,然后把字体关联到这个CSS样式. 一个快速的 ...

  5. 【BZOJ】3172: [Tjoi2013]单词(后缀自动机)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3172 随便搞个sam就行了.(其实一开始看到数据n<=200, 单词长度不超过1e6,然后感觉 ...

  6. 学习:erlang正则

    一.re:run/3. ①.re:run("321321","2132",[caseless]).     {match,[{1,4}]} %% 返回值是 匹配 ...

  7. c# http请求添加cookie

    CookieCollection cookList = new CookieCollection(); cookList.Add(new Cookie("cf_clearance" ...

  8. MyBitis(iBitis)系列随笔之一:MyBitis入门实例

        MyBits前身是iBitis,相对于Hibernate而言,它是半自动化ORM框架.本着分享和学习的目的,笔者将陆续把学习笔记与代码贴出,希望对想学习mybitis的同窗们有所帮助.     ...

  9. Mac 安装Jupyter notebook

    python:mac下自带Python 2.7.10 1.先升级了pip安装工具:sudo python -m pip install --upgrade --force pip 2.安装setupt ...

  10. VC++ 轻松实现“闪屏” SplashWnd

    我们平时使用的好多软件在运行启动时都会有一个“闪屏”画面显示,一般用于标识软件的一些信息,如软件版本名称.公司等,通过查找资料发现,其实实现起来很简单,一个类就能搞定! SplashWnd.h  C+ ...