- 浏览: 13015 次
- 性别:
- 来自: 厦门
最新评论
为什么你应该使用PHP PDO访问数据库
许多PHP程序员学习过如歌使用MySQL或MySQL扩展来访问数据库. 不过,自PHP 5.1版本以来,一个更好的解决方案出现了. PHP Data Objects (PDO) 提供了让你更有{productive}的准备{statements},处理对象的方法.
PDO 简介
“PDO – PHP Data Objects – is a database access layer providing a uniform method of access to multiple databases.”
它不受数据库特定语法限制, 但它可以让切换数据库和平台的过程更无痛,更简洁的切换数据库连接字符串.
这个教程并是一个完全的SQL入门. 它主要是为了帮助那些已经在使用MySQL或MySQLi扩展的人们过渡到更加强大、兼容性更好的PDO.
数据库支持
这个扩展能支持任何为PDO设计了驱动的数据库. 在写这篇文章的时候,以下数据库已经被支持:
- PDO_DBLIB ( FreeTDS / Microsoft SQL Server / Sybase )
- PDO_FIREBIRD ( Firebird/Interbase 6 )
- PDO_IBM ( IBM DB2 )
- PDO_INFORMIX ( IBM Informix Dynamic Server )
- PDO_MYSQL ( MySQL 3.x/4.x/5.x )
- PDO_OCI ( Oracle Call Interface )
- PDO_ODBC ( ODBC v3 (IBM DB2, unixODBC and win32 ODBC) )
- PDO_PGSQL ( PostgreSQL )
- PDO_SQLITE ( SQLite 3 and SQLite 2 )
- PDO_4D ( 4D )
所有这些驱动都没有被您的系统预装,这里有一种快速的方式来找到您需要的驱动:
print_r(PDO::getAvailableDrivers());
连接
不同的数据库可能在连接方法上有那么一点点的不同. 下面,我们将介绍几种常见的数据库的连接方法. 你将会注意到前三种看起来差不多, 不过像SQLite之类的语言就有他自己独特的语法.
try { //MS SQL Server and Sybase with PDO_DBLIB $DBH = new PDO(“mssql:host=$host;dbname=$dbname, $user, $pass”); $DBH = new PDO(“sybase:host=$host;dbname=$dbname, $user, $pass”); //MySQL with PDO_MYSQL $DBH = new PDO(“mysql:host=$host;dbname=$dbname”, $user, $pass); // SQLite Database $DBH = new PDO(“sqlite:my/database/path/database.db”); } catch(PDOException $e) { echo $e->getMessage(); }
请注意try/catch代码块 – 您应该始终将您 PDO 的操作封装在一个 try/catch 代码块内并使用异常机制 .通常你只会使用单个连接 – 下面将为您介绍它的语法.
下文中出现的 $DBH 意思是 ‘database handle’.
你可以通过把handle设置为null来关闭任何数据库连接.
// close the connection
$DBH = null;
你可以从 PHP.net 获取更多关于特点数据库的选项和连接字串(connection strings)的信息
异常处理
PDO 可以使用异常(Exceptions)来处理错误,这意味你需要把{处理PDO的}包括在一个try/catch代码块. 你也可以通过设置错误模式(error mode attribute)强制PDO在您最近创建的数据库连接上使用这三种错误模式中的一种. 以下提供了语法:
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT ); $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING ); $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
不过不管您设置什么错误模式, 错误的连接总会产生一个异常, 所以您应该在创建一个数据库时包含一个try/catch代码块.
PDO::ERRMODE_SILENT
这是默认的错误模式. 如果您使用了这种错误模式, 你将像您用mysql或mysqli扩展的时候那样自己检查错误. 这里还有两种更理想的符合[[DRY programming]]思想的方法.
PDO::ERRMODE_WARNING
这种模式将会发出(issue)一个标准的PHP warning,然后继续执行程序. 这种方法在调试时会很有用.
PDO::ERRMODE_EXCEPTION
这也许是人们在大多数情况下希望使用的模式. 它抛出(fire)一个异常, 允许你优雅的处理错误并且隐藏那些可能会导致安全风险的数据. 这里是一个处理异常的实例:
// connect to the database try { $DBH = new PDO(“mysql:host=$host;dbname=$dbname”, $user, $pass); $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); // UH-OH! Typed DELECT instead of SELECT! $DBH->prepare(‘DELECT name FROM people’); } catch(PDOException $e) { echo “I’m sorry, Dave. I’m afraid I can’t do that.”; file_put_contents(‘PDOErrors.txt’, $e->getMessage(), FILE_APPEND); }
上面是一个在select statement中的内部错误; 这将会引发一个异常. 这段异常处理代码将会把错误详情发送到一个日志文件中, 然后显示一个友好的(当然,友不友好随你便)消息给用户.
插入、更新数据
插入新数据、或更新一个已经存在的数据,是最常见的数据库操作之一. PDO提供了一种[[normally a two-step process]]. 本节中介绍的所有内容同样适用于 UPDATE 和 INSERT 操作.
下面是一个最基本的插入的例子:
// STH means “Statement Handle” $STH = $DBH->prepare(“INSERT INTO folks ( first_name ) values ( ‘Cathy’ )”); $STH->execute();
您也可以直接使用exec()方法完成相同的操作(PS:使用exec()方法可以减少一个调用). 在大多数情况下,您可能会多次调用这个方法, 所以呢, 您可以享受到prepared statements带来的好处. 甚至如果您只想调用它一次, 使用prepared statements will 也会帮您挡住 SQL injection 攻击.
Prepared Statements
使用 prepared statements 将帮助您防止 SQL injection 的危险.
Prepared statement的语句是只需要发送数据到服务器的预编译 SQL 语句, 它具有自动处理数据以免受 SQL injection 攻击的优点。
您可以通过在您的SQL语句中包含占位符来使用 prepared statement . 这里有三个例子: 一个没有占位符的, 一个有未命名占位符(Unnamed Placeholders)的, 和一个有命名占位符(Named Placeholders)的.
// no placeholders – ripe for SQL Injection! $STH = $DBH->(“INSERT INTO folks (name, addr, city) values ($name, $addr, $city)”); // unnamed placeholders $STH = $DBH->(“INSERT INTO folks (name, addr, city) values (?, ?, ?); // named placeholders $STH = $DBH->(“INSERT INTO folks (name, addr, city) value (:name, :addr, :city)”);
您可能想避免使用第一种方法; 下面为您提供了它们直接的比较. 选择未命名占位符或命名占位符将会影响您如何为这些语句设置数据.
未命名占位符(Unnamed Placeholders)
// assign variables to each place holder, indexed 1-3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $city); // insert one row $name = “Daniel” $addr = “1 Wicked Way”; $city = “Arlington Heights”; $STH->execute(); //insert another row with different values $name = “Steve” $addr = “5 Circle Drive”; $city = “Schaumburg”; $STH->execute();
只需两步!首先,我们为不同的占位符(Placeholder)绑定变量 (lines 2-4). 然后,我们为那些占位符(Placeholder)赋值然后执行查询. 要想发送另外的一组数据,只需要改变那些变量的值,然后再执行即可.
(译注: 原文在第一步与第二布均使用了assign来描述过程)
这个使用很多参数的方法似乎有点麻烦?如果您的数据存储在数组中,有一个简单的方法:
// the data we want to insert $data = array(‘Cathy’, ’9 Dark and Twisty Road’, ‘Cardiff’); $STH = $DBH->(“INSERT INTO folks (name, addr, city) values (?, ?, ?); $STH->execute($data);
这很简单,不是吗?
在数组中的数据等同于占位符。 $data[0]对应第一个占位符,$data[1]第二个,依此类推,但如果您的数组索引并未排序,这将无法正常工作,您将需要重新索引这个数组.
命名占位符(Named Placeholders)
您可能已经猜到语法了,下面给出了一个例子:
//the first argument is the named placeholder name – notice named // placeholders always start with a colon. $STH->bindParam(‘:name’, $name);
您也可以在这里使用一个快捷方式,但它可以和关联数组一起使用.
// the data we want to insert $data = array( ‘name’ => ‘Cathy’, ‘addr’ => ’9 Dark and Twisty’, ‘city’ => ‘Cardiff’ ); // the shortcut! $STH = $DBH->(“INSERT INTO folks (name, addr, city) value (:name, :addr, :city)”); $STH->execute($data);
你的数组中的键不需要以一个冒号开始,但是必须符合指定的占位符。如果你有一个二维数组(就是数组中的数组),您可以遍历它们,只需调用执行的每个数据的数组。
另一个命名占位符不错的特点是直接可以插入对象到您的数据库,如果命名的属性匹配字段的话.下面是一个例子对象:
// a simple object class person { public $name; public $addr; public $city; function __construct($n,$a,$c) { $this->name = $n; $this->addr = $a; $this->city = $c; } // etc … } $cathy = new person(‘Cathy’,’9 Dark and Twisty’,'Cardiff’); // here’s the fun part: $STH = $DBH->(“INSERT INTO folks (name, addr, city) value (:name, :addr, :city)”); $STH->execute((array)$cathy);
在执行中,对象被转换为一个数组.对象的属性被视为数组中的一个键. By casting the object to an array in the execute, the properties are treated as array keys.
选择数据
数据通过fetch()方法获得, {一种应用于陈述式句柄的方法}. 在使用fetch之间, 您最好告诉PDO您喜欢取得数据的样子. 您有以下几个选择:
- PDO::FETCH_ASSOC: 返回一个包含列名索引的数组
- PDO::FETCH_BOTH (default): 返回一个由同时包含列名和数字索引的数组
- PDO::FETCH_BOUND: 通过 ->bindColumn() 方法将列的值赋到变量上。
- PDO::FETCH_CLASS:列的值赋给指定对象的属性里。如果指定的属性不存在,会自动创建。
- PDO::FETCH_INTO: 更新一个已经存在的命名对象的实例
- PDO::FETCH_LAZY: 结合 了PDO::FETCH_BOTH,PDO::FETCH_OBJ,在它们被调用时创建对象变量
- PDO::FETCH_NUM: 返回一个由同时包含列数字索引的数组
- PDO::FETCH_OBJ: fanhuire返回一个有对应的列名的属性的匿名对象
在现实中,大多数情况下会使用以下三种: FETCH_ASSOC, FETCH_CLASS, FETCH_OBJ. 您需要使用以下语法设置获取类型:
$STH->setFetchMode(PDO::FETCH_ASSOC);
您也可以直接在fetch()方法中设置获取模式.
FETCH_ASSOC
这种模式创建一个按列名索引的关联数组.这应该会让用过MySQL/MySQLi扩展的人感到亲切.这里有一个使用这种方法选择数据的例子.
// using the shortcut ->query() method here since there are no variable // values in the select statement. $STH = $DBH->query(‘SELECT name, addr, city from folks’); // setting the fetch mode $STH->setFetchMode(PDO::FETCH_ASSOC); while($row = $STH->fetch()) { echo $row['name'] . “n”; echo $row['addr'] . “n”; echo $row['city'] . “n”; }
这个 while 循环将在获取完所有数据后停止.{The while loop will continue to go through the result set one row at a time until complete.}
FETCH_OBJ
这种模式为每一行数据创建一个标准类,下面是一个例子:
// creating the statement $STH = $DBH->query(‘SELECT name, addr, city from folks’); // setting the fetch mode $STH->setFetchMode(PDO::FETCH_OBJ); // showing the results while($row = $STH->fetch()) { echo $row->name . “n”; echo $row->addr . “n”; echo $row->city . “n”; }
FETCH_CLASS
您的对象的属性应该在constructor被调用前设置!这一点很重要!
这种模式允许你直接将获取的数据发送到您选择的类中.当您使用FETCH_CLASS时,您的对象的属性应该在constructor被调用前设置。读一遍,它是重要的。如果属性相匹配的列名不存在,这些属性将被创建,(公共)为您。
这意味着如果你需要转换后出来的数据,它可以通过你的对象自动为转换.
举个列子,假设的情况下该地址必须为特定格式,我们可以通过constructor上做到这一点,下面是一个例子:
class secret_person { public $name; public $addr; public $city; public $other_data; function __construct($other = ”) { $this->address = preg_replace(‘/[a-z]/’, ‘x’, $this->address); $this->other_data = $other; } }
OK,再让我们看看效果如何?
$STH = $DBH->query(‘SELECT name, addr, city from folks’); $STH->setFetchMode(PDO::FETCH_CLASS, ‘secret_person’); while($obj = $STH->fetch()) { echo $obj->addr; }
如果地址是,‘5 Rosebud,’ 您将会在输出中看到 ‘5 Rxxxxxx’. 当然,可能有些情况下,您希望在constructor函数在数据被赋值之前调用.PDO也可以做到~
现在,当你使用这个模式(PDO::FETCH_PROPS_LATE)的地址不会被遮,constructor会被首先调用然后再赋值.
最后,如果你真的需要,你可以在使用PDO获取数据到对象时,将参数传递给构造函数:
如果你需要传递不同的数据到每个对象的构造函数,你可以设置在fetch方法内设置模式法模式:
$i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, ‘secret_person’, array($i))) { // do stuff $i++ }
其他有用的方法
虽然 PDO 并没有面面俱到的(这扩展可不小!), 这里仍还还有一些您想知道的方法.
$DBH->lastInsertId();
lastInsertId()方法始终调用数据库句柄,而不是表达式的句柄,并且会返回该数据库连接上一次插入语句的自增ID.
$DBH->exec(‘DELETE FROM folks WHERE 1′);
$DBH->exec(“SET time_zone = ‘-8:00′”);
exec()方法用于那些不能返回数据或不影响行的操作. 上面是两种调用exec()方法的例子.
$safe = $DBH->quote($unsafe);
quote() 方法将字符转义为安全的字符以便在查询中使用. 如果您不使用已经准备号的语句,您可以用此方法<<*>>。
$rows_affected = $STH->rowCount();
rowCount() 方法返回一个表明被一个操作影响的行数的整数(简直是废话,难不成还是浮点数?). 更具这个错误报告(http://bugs.php.net/40822) ,在最近的一个PDO版本上这个方法不能够很好的与SELECT语句工作. 如果您遇到了这个问题而不想升级PHP的话, 你可以用以下的方法来替代它:
$sql = “SELECT COUNT(*) FROM folks”; if ($STH = $DBH->query($sql)) { // check the row count if ($STH->fetchColumn() > 0) { // issue a real select here, because there’s data! } else { echo “No rows matched the query.”; } }
结尾
我希望这篇文章能帮助您从mysql和mysqli扩展迁移至PDO.您有啥想法?现在想迁移到PDO么?
英文原文:http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
相关推荐
PDO是PHP提供的一种数据库访问层,它提供了统一的API(应用程序编程接口),使得在不同类型的数据库之间切换变得更加容易。 描述中提到的主要功能包括基本的数据库连接、数据的增删改查以及关闭连接。这个操作类...
PHP PDO(PHP Data Objects)是PHP5中引入的一个数据库访问抽象层扩展,它提供了一个统一的方法访问多种数据库。通过PDO,可以使用相同的函数来操作不同的数据库,从而降低了因数据库不同而造成的代码差异。PDO支持...
- **PHPPDO类**:这里指的是使用PHP编写的自定义PDO数据库操作类。 综上所述,PHP-PDO数据库操作类是为简化数据库操作和提高安全性而设计的。通过自定义PDO类,可以更好地组织和管理数据库相关的代码,同时充分...
PHP PDO,即PHP数据对象,是一个数据库访问抽象层,提供了统一的接口来访问各种不同的数据库系统。它旨在提供一个统一的方法来处理数据,而无需考虑底层数据库的实际类型。PDO的主要优势包括: 1. **数据库抽象**:...
PDO(PHP Data Objects)是PHP语言中用于数据库访问的一个扩展,提供了一种统一的API来访问多种数据库系统。本资源包含一个PHP PDO数据库操作类,旨在简化数据库交互,支持多种调试模式,以适应不同开发阶段的需求。...
在PHP5中,PDO(PHP Data Objects)扩展提供了一种通用的、轻量级的、面向对象的方式来访问各种数据库。PDO为开发者提供了统一的API接口,可以方便地切换不同的数据库管理系统(DBMS),如MySQL、SQLite、PostgreSQL...
能使用PDO扩展本身执行任何数据库操作,必须使用一个database-specific PDO driver(针对特定数据库的PDO驱动)访问数据库 PDO开启:修改php.ini文件,extension=php_pdo.dll,分号删除就是开启PDO 另外还有PDO其他...
PDO 扩展为 PHP 访问数据库定义的一个轻量级的、一致性的接口。它提供了一个数据访问抽象层,这样无论使用什么数据库,都可以通过一致的函数执行查询和获取数据。 PDO 扩展具有很强的实际应用价值,主要体现在以下...
讲述了PHP实现PDO的mysql数据库操作类,dbconfig类负责配置数据库访问信息,包括:服务器地址、端口、数据库实例名、用户名、用户密码、字符集等。 dbtemplate类集合了对数据库的访问操作,主要有以下几个操作: 1. ...
PDO(PHP Data Objects)是PHP的一个扩展,提供了一种统一的方式来访问各种数据库,包括Oracle。本文将详细介绍如何使用PHP PDO连接Oracle数据库,以及提供的资源如何帮助解决问题。 首先,让我们理解PHP PDO的基本...
讲述了PHP实现PDO的mysql数据库操作类,dbconfig类负责配置数据库访问信息,包括:服务器地址、端口、数据库实例名、用户名、用户密码、字符集等。 dbtemplate类集合了对数据库的访问操作,主要有以下几...
PDO 是 PHP 中用于访问数据库的扩展,提供了统一的数据库访问接口,支持多种数据库系统。 #### 3.2 连接数据库 - **PDO 支持的数据库类型** 包括 MySQL、SQLite、PostgreSQL 等。 - **连接数据库** 的一般格式为:`...
PDO是PHP提供的一种数据库访问接口,旨在为不同的数据库系统提供一个统一的访问方式,使得开发人员无需因数据库类型的不同而改变代码。 描述中提到,PDO是一个数据库操作的公用类,它提供了轻量级且一致的接口。这...
PDO(PHP Data Objects)是一个数据库访问抽象层,提供了一个一致的接口来访问多种数据库。然而,在使用PDO与数据库交互时,常常会遇到乱码问题,尤其是在处理中文字符时。本文主要讨论在使用PDO操作数据库时解决...
在PHP编程中,PDO(PHP Data Objects)是一个数据库访问层,提供了一种统一的方式来连接不同的数据库。PDO提供了预处理语句、事务处理等高级特性,增强了安全性并提高了性能。本篇文章将通过一个简单的实例,介绍...
在PHP开发中,PDO(PHP Data Objects)是一个强大的数据库访问层,它提供了统一的API来连接多种数据库系统,如MySQL、PostgreSQL、SQLite等。PDO不仅提高了代码的可移植性,还提供了预处理语句,增强了安全性,防止...
首先,PDO(PHP Data Objects)是PHP中的一套数据库访问层,提供了一种统一的API来访问多种数据库系统,包括Oracle。而oci(Oracle Call Interface)是Oracle提供的C语言接口,用于在非Oracle环境下与Oracle数据库...
综上所述,"PHP经典实例--访问数据库"涵盖的内容包括但不限于:DBM与SQL数据库的区别、PDO扩展的使用、连接数据库的方法、执行SQL查询和预处理语句。这个主题对于任何想要提升PHP数据库编程技能的人来说都是宝贵的...
系统使用MySQL数据库存储数据,采用PDO方式进行数据库访问。系统的实现过程主要包括以下几个方面: - 界面设计:采用Bootstrap框架进行界面设计,使界面简洁明了,易于操作; - 数据库设计:设计数据库结构,建立...