PHP扩展之PDO

PHP 阅读: 402

PDO介绍

PDO是 PHP Data Oject 的缩写,即PHP数据对象。提供了访问各种数据库的一致接口,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。

PDO还提供了预处理功能来防止SQL注入,另外也可以使用事务功能。

安装PDO扩展

PHP在安装的时候,已经默认安装了PDO扩展,但要使用PDO操作具体的数据库,需要安装相应的数据库驱动扩展pdo-dbname。安装扩展的方法这里不做说明。

要查看PDO支持哪些数据库驱动,点击这里:PHP: PDO 驱动 - Manual

使用PDO连接数据库

下面使用PDO连接本地的MySQL数据库,先实例化一个PDO对象:

$pdo = new PDO('mysql:host=localhost;port=3306;dbname=test;charset=utf8', 'root', '123456');

第一个参数为数据源名称,其中mysql为数据库名称(小写),:号后面的参数有:

  • host:数据库主机地址,本地可以填localhost127.0.0.1,默认本机。
  • port:数据库服务端口号,默认端口3306。
  • dbname:要选择数据库名称,这里可以不写,之后可以用执行use dbname选择。但注意要有改数据库的操作权限。
  • charset:传输数据使用的字符集,默认`utf8。

第二个参数为连接数据库的用户名,第三个参数为用户密码。

其实还有第四个参数,用来设置连接参数,请参考PHP手册:https://www.php.net/manual/zh/pdo.setattribute.php

如果连接出现错误,将抛出一个 PDOException 异常对象,你可以使用 try-catch 语句捕获它。

执行SQL查询

执行一条SQL查询很简单:

$sql = "select * from tb_user";
$statement = $pdo->query($sql);

query方法执行一条SQL语句,查询失败返回false,成功返回一个PDOStatement对象。

PDOStatement是PDO语句类,用来获取查询语句结果、执行预处理语句。

获取错误信息

先看看执行失败时候如何获取错误信息,PDO类提供两个方法:

// 返回一个SQLSTATE,由5个字母或数字组成的在 ANSI SQL 标准中定义的标识符。
public PDO::errorCode ( void ) : mixed

// 获取最后一个操作相关的错误信息(包含了errorCode,所以一般使用这个)
public PDO::errorInfo ( void ) : array

errorInfo方法返回的数组结构如下:

元素 说明信息
0 SQL 错误状态码
1 驱动指定的错误码
2 驱动指定的错误信息

获取查询结果

如果执行的是 select 语句,并且语句执行成功,则可以通过 query() 方法返回的PDOStatement对象获取查询的结果。PDOStatement类相关的方法有:

// 一般来说如果语句无返回数据使用`rowCount`获取SQL语句影响的行数即可,如insert、delete、update等语句。
public PDOStatement::rowCount() — 返回受上一个SQL语句影响的行数

// 如果有返回数据使用下面的方法,如select语句。
public PDOStatement::columnCount() — 返回结果集中的列数
public PDOStatement::setFetchMode() — 为语句设置默认的获取模式。
public PDOStatement::bindParam() — 绑定一个参数到指定的变量名
public PDOStatement::fetch() — 从结果集中获取下一行
public PDOStatement::fetchAll() — 返回一个包含结果集中所有行的数组
public PDOStatement::fetchColumn() — 从结果集中的下一行返回单独的一列。
public PDOStatement::fetchObject() — 获取下一行并作为一个对象返回。

查看各个函数的具体用法点这里:PHP: PDOStatement - Manual

这里介绍一般获取 select 语句返回数据的用法:

// 设置获取的数据为关联数组(推荐)
$statement->setFetchMode(PDO::FETCH_ASSOC);

// 一行一行的获取
while ($row = $statement->fetch()) {
    print_r($row);
}

// 一次全部取出
$rows = $statement->fetchAll();
print_r($rows);

使用预处理防止SQL注入

PDO一个强大的功能就是提供了预处理功能,通过先设置SQL语句格式,然后再绑定具体查询参数,可以有效的防止SQL注入攻击。

要使用预处理,先调用PDO对象的prepare()方法来设置的SQL语句格式,该方法返回一个PDOStatement对象,接着使用PDOStatement对象的execute()方法绑定具体的参数并执行查询:

$sql = "select * from tb_user where id = :id and password = :password";
$statement = $pdo->prepare($sql); // 设置SQL语句格式
// 准备查询参数
$args = [
    ':id' => 1004,
    ':password' => '123456',
];
$res = $statement->execute($args); // 绑定参数并执行查询

上面使用了名称占位符:id:password,还可以使用通用占位符?。如果使用了通用占位符,那么绑定的参数的时候不需要指定名称,按顺序传入即可,就像这样:

$sql = "select * from tb_user where id = ? and password = ?";
$statement = $pdo->prepare($sql);
$args = [1004, '123456'];
$res = $statement->execute($args);

还可以不一次性绑定所有参数,而是以一个一个的绑定参数值:

// (1)通过序号绑定
$sql = "select * from tb_user where id = ? and password = ?";
$statement = $pdo->prepare($sql);
$statement->bindValue(1, 1004, PDO::PARAM_INT);
$statement->bindValue(2, '123456', PDO::PARAM_STR);
$res = $statement->execute();

// (2)通过名称占位符绑定
$sql = "select * from tb_user where id = :id and password = :password";
$statement = $pdo->prepare($sql); // 设置SQL语句格式
$statement->bindValue(':id', 1004, PDO::PARAM_INT);
$statement->bindValue(':password', '123456', PDO::PARAM_STR);
$res = $statement->execute();

使用bindValue()方法可以一个个绑定参数,并且它的第三个参数可以指定参数类型,默认为PDO::PARAM_STR,要查看全部的类型可以点击这里:PDO预定义常量

bindValue()方法类似的还有bindParam()方法,它们的参数相同,不同的是变量作为引用被绑定,并只在execute()被调用的时候才取其值。

execute()方法会返回一个bool值表示查询是否成功,如果返回false你可以使用下面两个方法获取错误信息:

// 返回一个 SQLSTATE,由5个字母或数字组成的在 ANSI SQL 标准中定义的标识符。
public PDOStatement::errorCode ( void ) : mixed

// 获取最后一个操作相关的错误信息(包含了errorCode,所以一般使用这个)
public PDOStatement::errorInfo ( void ) : array

使用事务

PDO提供了事务功能,相关的方法如下:

// 启动一个事务
public PDO::beginTransaction ( void ) : bool
// 提交一个事务
public PDO::commit ( void ) : bool
// 回滚一个事务
public PDO::rollBack ( void ) : bool

如果底层数据库驱动不支持事务,则beginTransaction()方法会抛出一个PDOException异常。

使用例子:

try { 
    // 开始一个事务,关闭自动提交
    $pdo->beginTransaction();

    // 开始SQL查询,可以使用预处理
    $sth = $pdo->exec("UPDATE dessert SET name = 'hamburger'");
    $sql = 'INSERT INTO fruit(name, colour, calories) VALUES (?, ?, ?)';
    $sth = $dbh->prepare($sql);
    foreach ($fruits as $fruit) {
        $sth->execute(array(
            $fruit->name,
            $fruit->colour,
            $fruit->calories,
        ));
    }
    // 提交
    $pdo->commit();
} catch (Exception $e) { // 发生错误则回滚
  $pdo->rollBack();
  echo $e->getMessage();
}

// 此时数据库连接恢复到自动提交模式

参考文章

  1. PHP手册:PHP: PDO - Manual

版权声明:本文为博主原创文章,转载需注明来自: 洛洛の空间