PHP 7: 真实世界的应用开发
  • 前言
  • 模块一
    • 第一章、建立基础
      • PHP 7 安装注意事项
      • 使用内置的 PHP web 服务器
      • 创建一个 MySQL 测试数据库
      • 安装 PHPUnit
      • 实现类的自动加载
      • 抓取一个网站
      • 建立一个深度网络扫描器
      • 创建一个 PHP 5 到 PHP 7 代码转换器
    • 第二章、使用 PHP 7 高性能特性
      • 了解抽象语法树
      • 理解句法分析中的差异
      • 理解 foreach() 处理中的差异
      • 使用 PHP 7 增强功能提高性能
      • 遍历海量文件
      • 将电子表格上传到数据库
      • 递归目录迭代器
    • 第三章、使用 PHP 函数
      • 函数开发
      • 数据类型提示
      • 使用返回值数据类型
      • 使用迭代器
      • 使用生成器编写自己的迭代器
    • 第四章、使用 PHP 面向对象程序设计
      • 类的开发
      • 类的扩展
      • 使用静态属性和方法
      • 使用命名空间
      • 定义可见性
      • 使用接口
      • 使用特性
      • 实现匿名类
    • 第五章、与数据库的交互
      • 使用PDO连接数据库
      • 构建一个 OOP SQL 查询生成器
      • 处理分页
      • 定义实体以匹配数据库表
      • 将实体类与RDBMS查询绑定
      • 将二次查找嵌入到查询结果中
      • 实现jQuery DataTables的PHP查找
    • 第六章、建立可扩展的网站
      • 创建通用表单元素生成器
      • 创建一个HTML单选元素生成器
      • 创建一个HTML选择元素生成器
      • 实现表单工厂
      • 链式 $_POST 过滤器
      • 链式 $_POST 验证器
      • 将验证绑定到表单
    • 第七章、访问Web服务
      • 在PHP和XML之间转换
      • 创建一个简单的REST客户端
      • 创建一个简单的REST服务器
      • 创建一个简单的SOAP客户端
      • 创建一个简单的SOAP服务器
    • 第八章、处理日期/时间和国际化方面
      • 在视图脚本中使用 emoji
      • 转换复杂字符
      • 从浏览器数据获取语言环境
      • 按地区设置数字格式
      • 按地区处理货币
      • 按地区设置日期/时间格式
      • 创建一个HTML国际日历生成器
      • 构建一个周期性事件生成器
      • 不使用gettext处理翻译
    • 第九章、开发中间件
      • 使用中间件进行认证
      • 使用中间件实现访问控制
      • 使用高速缓存提高性能
      • 实施路由选择
      • 进行框架间的系统调用
      • 使用中间件来跨语言
    • 第十章、高级算法
      • 使用 getter 和 setter
      • 实现一个链表
      • 建立冒泡排序
      • 实现一个堆栈
      • 构建一个二分法查找类
      • 实现一个搜索引擎
      • 显示多维数组并累计总数
    • 第十一章、软件设计模式的实现
      • 创建数组到对象的转化器
      • 构建对象到数组到转化器
      • 实施策略模式
      • 定义一个映射器
      • 实现对象关系映射
      • 实施发布/订阅设计模式
    • 第十二章、提高网站安全
      • 过滤$_POST数据
      • 验证$_POST数据
      • 保护PHP session
      • 用令牌保护表格的安全
      • 建立一个安全的密码生成器
      • 带有验证码的安全保护表格
      • 不使用mcrypt进行加密/解密
    • 第十三章、最佳实践、测试和调试
      • 使用特征和接口
      • 通用异常处理程序
      • 通用错误处理程序
      • 编写一个简单的测试
      • 编写测试套件
      • 生成虚假的测试数据
      • 使用session_start参数自定义会话
    • PSR-7
  • 模块二
  • 模块三
    • GoF 设计模式
      • 结构型
      • 行为型
      • 小结
    • SOLID 设计原则
      • 开闭原则
      • 里氏替换原则
      • 接口隔离原则
      • 依赖反转原则
      • 小结
    • 模块化网店应用的需求规范
      • 线框设计
      • 定义技术栈
      • 小结
    • Symfony 概述
      • 创建一个空白项目
      • 使用 Symfony 控制台
      • 控制器
      • 路由
      • 模板
      • 表单
      • 配置 Symfony
      • bundle 系统
      • 数据库和 Doctrine
      • 测试
      • 验证
      • 小结
    • 构建核心模块
    • 构建目录模块
    • 构建客户模块
    • 构建支付模块
    • 构建发货模块
    • 构建销售模块
    • 总结
由 GitBook 提供支持
在本页
  • 如何做...
  • 如何运行...
  • 参考
  1. 模块一
  2. 第五章、与数据库的交互

使用PDO连接数据库

PDO是一个高性能和积极维护的数据库扩展,与特定数据库的扩展相比,它具有独特的优势。它有一个通用的应用编程接口(API),可以兼容几乎十几种不同的关系型数据库管理系统(RDBMS)。学习如何使用这个扩展将节省您试图掌握同等的单个数据库扩展命令子集的时间。

PDO又分为四个主要类,如下表所示:

类

功能

PDO

保持与数据库的实际连接,并处理更底层功能,如事务支持。

PDOStatement

处理结果

PDOException

数据库特有的异常

PDODriver

与各数据库进行通信

如何做...

1.通过创建 PDO 实例来设置数据库连接。

2. 您需要构建一个数据源名称(DSN)。DSN中包含的信息根据使用的数据库驱动程序而不同。举个例子,这里是一个用于连接到MySQL数据库的DSN。

$params = [
  'host' => 'localhost',
  'user' => 'test',
  'pwd'  => 'password',
  'db'   => 'php7cookbook'
];

try {
  $dsn  = sprintf('mysql:host=%s;dbname=%s',
  $params['host'], $params['db']);
  $pdo  = new PDO($dsn, $params['user'], $params['pwd']);
} catch (PDOException $e) {
  echo $e->getMessage();
} catch (Throwable $e) {
  echo $e->getMessage();
}

3.而 SQlite 一个更简单的扩展,只需要以下命令。

$params = [
  'db'   => __DIR__ . '/../data/db/php7cookbook.db.sqlite'
];
$dsn  = sprintf('sqlite:' . $params['db']);

4. 而 PostgreSQL 则在DSN中直接包含了用户名和密码。

$params = [
  'host' => 'localhost',
  'user' => 'test',
  'pwd'  => 'password',
  'db'   => 'php7cookbook'
];
$dsn  = sprintf('pgsql:host=%s;dbname=%s;user=%s;password=%s', 
               $params['host'], 
               $params['db'],
               $params['user'],
               $params['pwd']);

5.DSN还可以包含特定于服务器的指令,例如 unix_socket,如下例所示。

$params = [
  'host' => 'localhost',
  'user' => 'test',
  'pwd'  => 'password',
  'db'   => 'php7cookbook',
  'sock' => '/var/run/mysqld/mysqld.sock'
];

try {
  $dsn  = sprintf('mysql:host=%s;dbname=%s;unix_socket=%s', 
                  $params['host'], $params['db'], $params['sock']);
  $opts = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION];
  $pdo  = new PDO($dsn, $params['user'], $params['pwd'], $opts);
} catch (PDOException $e) {
  echo $e->getMessage();
} catch (Throwable $e) {
  echo $e->getMessage();
}

将创建PDO实例的语句封装在 try {} catch {} 块中。在失败的情况下,捕获 PDOException来获取数据库的特定信息。抓取Throwable来处理错误或其他异常。将PDO错误模式设置为 PDO::ERRMODE_EXCEPTION以 获得最佳效果。关于错误模式的更多细节请参见步骤8。

在PHP 5中,如果PDO对象不能被构造(例如,当使用无效参数时),实例被分配一个NULL值。在 PHP 7 中,会抛出一个 Exception。如果把PDO对象的构造包在try {} catch {}块中,并且PDO::ATTR_ERRMODE设置为PDO::ERRMODE_EXCEPTION,就可以捕捉和记录这样的错误,而不需要测试NULL。

6.使用 PDO::query() 发送一个SQL命令。返回一个 PDOStatement 实例,您可以根据它来获取结果。在这个例子中,我们正在寻找按ID排序的前20位客户。

$stmt = $pdo->query(
'SELECT * FROM customer ORDER BY id LIMIT 20');

PDO还提供了一个便利的方法 PDO::exec(),它不返回结果迭代,只返回受影响的行数。这个方法最好用于管理操作,比如 ALTER TABLE,DROP TABLE等。

7.遍历 PDOStatement 实例来处理结果。设置获取模式为 PDO::FETCH_NUM或 PDO::FETCH_ASSOC,以数字或关联数组的形式返回结果。在这个例子中,我们使用一个 while() 循环来处理结果。当最后一个结果被获取后,结果是一个布尔值 FALSE,结束循环。

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  printf('%4d | %20s | %5s' . PHP_EOL, $row['id'], 
  $row['name'], $row['level']);
}

PDO获取操作涉及游标,这个游标定义了迭代的方向(即正向或反向)。PDOStatement::fetch() 的第二个参数可以是 PDO::FETCHORI_* 常量中的任何一个。游标方向包括 prior、first、last、absolute 和 relative。默认的游标方向是 PDO::FETCH_ORI_NEXT。

8.将获取模式设置为 PDO::FETCH_OBJ,以 stdClass 实例的形式返回结果。这里您会注意到,while()循环利用了 PDO::FETCH_OBJ 的获取模式。请注意,printf() 语句引用的是对象属性,而前面的例子引用的是数组元素。

while ($row = $stmt->fetch(PDO::FETCH_OBJ)) {
  printf('%4d | %20s | %5s' . PHP_EOL, 
  $row->id, $row->name, $row->level);
}

9.如果你想在处理查询时创建一个特定类的实例,请将获取模式设置为 PDO::FETCH_CLASS。您还必须有类的定义,PDO::query() 应该设置类名。在下面的代码片段中可以看到,我们定义了一个名为 Customer的类,具有公共属性 $id、$name和$level。属性需要是公共的,这样取值注入才能正常工作。

class Customer
{
  public $id;
  public $name;
  public $level;
}

$stmt = $pdo->query($sql, PDO::FETCH_CLASS, 'Customer');

10.当获取对象时,步骤5中所示的技术的更简单的替代方法是使用 PDOStatement::fetchObject()。

while ($row = $stmt->fetchObject('Customer')) {
  printf('%4d | %20s | %5s' . PHP_EOL, 
  $row->id, $row->name, $row->level);
}

11.您也可以使用 PDO::FETCH_INTO,它和 PDO::FETCH_CLASS 本质上是一样的,但是您需要一个对象实例而不是一个类引用。每一次循环的迭代都会用当前的信息集重新填充同一个对象实例。这个例子假设Customer 类和第5步一样,使用和第1步中定义的相同的数据库参数和PDO连接。

$cust = new Customer();
while ($stmt->fetch(PDO::FETCH_INTO)) {
  printf('%4d | %20s | %5s' . PHP_EOL, 
  $cust->id, $cust->name, $cust->level);
}

12.如果您没有指定错误模式,默认的PDO错误模式是 PDO::ERRMODE_SILENT。您可以使用PDO::ATTR_ERRMODE 作为键,然后 PDO::ERRMODE_WARNING或PDO::ERRMODE_EXCEPTION 作为值来设置错误模式。错误模式可以以关联数组的形式指定为PDO构造函数的第四个参数,也可以使用 PDO::ERRMODE_WARNING或PDO::ERRMODE_EXCEPTION。另外,你也可以在现有的实例上使用PDO::setAttribute()。

13. 让我们假设您有以下DSN和SQL(在开始认为这是一种新的SQL形式之前,请放心:这个SQL语句将无法使用!)。

$params = [
  'host' => 'localhost',
  'user' => 'test',
  'pwd'  => 'password',
  'db'   => 'php7cookbook'
];
$dsn  = sprintf('mysql:host=%s;dbname=%s', $params['host'], $params['db']);
$sql  = 'THIS SQL STATEMENT WILL NOT WORK';

14.如果你使用默认的错误模式制定你的PDO连接,唯一的线索就是 PDO::query() 将返回一个布尔值FALSE,而不是生成一个PDOStatement实例。

$pdo1  = new PDO($dsn, $params['user'], $params['pwd']);
$stmt = $pdo1->query($sql);
$row = ($stmt) ? $stmt->fetch(PDO::FETCH_ASSOC) : 'No Good';

15. 接下来的例子显示了使用构造函数方法将错误模式设置为WARNING。

$pdo2 = new PDO(
  $dsn, 
  $params['user'], 
  $params['pwd'], 
  [PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING]);

16.如果你需要将准备阶段和执行阶段完全分离,可以使用 PDO::prepare()和PDOStatement::execute()来代替。语句会被发送到数据库服务器进行预编译。然后你可以根据需要多次执行该语句,很可能是在一个循环中执行。

17.PDO::prepare()的第一个参数是一个SQL语句,用占位符代替实际值。然后可以向PDOStatement::execute()提供一个数组。PDO自动提供数据库引用,这有助于防止SQL注入。

最佳实践

任何将外部输入(即来自表单发布的输入)与SQL语句相结合的应用程序都会受到SQL注入攻击。所有的外部输入必须首先进行适当的过滤、验证和其他方面的校验。不要将外部输入直接放入SQL语句中。相反,使用占位符,并在执行阶段提供实际(经过校验)的值。

18.要以反向方式遍历结果,可以改变可滚动光标的方向。另外,可能更容易的是,只需将 ORDER BY从ASC反转到DESC。这行代码设置了一个PDOStatement对象,请求一个可滚动的游标。

$dsn  = sprintf('pgsql:charset=UTF8;host=%s;dbname=%s', $params['host'], $params['db']);
$opts = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]; 
$pdo  = new PDO($dsn, $params['user'], $params['pwd'], $opts);
$sql  = 'SELECT * FROM customer '
    . 'WHERE balance > :min AND balance < :max '
    . 'ORDER BY id LIMIT 20';
$stmt = $pdo->prepare($sql, [PDO::ATTR_CURSOR  => PDO::CURSOR_SCROLL]);

19. 你还需要在获取操作中指定游标指令。这个例子获取结果集中的最后一行,然后向后滚动。

$stmt->execute(['min' => $min, 'max' => $max]);
$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST);
do {
  printf('%4d | %20s | %5s | %8.2f' . PHP_EOL, 
       $row['id'], 
       $row['name'], 
       $row['level'], 
       $row['balance']);
} while ($row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_PRIOR));

20. MySQL和SQLite都不支持可滚动的光标! 为了达到同样的效果,请尝试对前面的代码进行以下修改。

$dsn  = sprintf('mysql:charset=UTF8;host=%s;dbname=%s', $params['host'], $params['db']);
$opts = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]; 
$pdo  = new PDO($dsn, $params['user'], $params['pwd'], $opts);
$sql  = 'SELECT * FROM customer '
    . 'WHERE balance > :min AND balance < :max '
    . 'ORDER BY id DESC 
       . 'LIMIT 20';
$stmt = $pdo->prepare($sql);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC));
printf('%4d | %20s | %5s | %8.2f' . PHP_EOL, 
       $row['id'], 
       $row['name'], 
       $row['level'], 
       $row['balance']);
} 

21. PDO提供了对事务的支持。借用步骤9中的代码,我们可以将 INSERT 系列命令包装成一个事务块。

try {
    $pdo->beginTransaction();
    $sql  = "INSERT INTO customer ('" 
    . implode("','", $fields) . "') VALUES (?,?,?,?,?,?)";
    $stmt = $pdo->prepare($sql);
    foreach ($data as $row) $stmt->execute($row);
    $pdo->commit();
} catch (PDOException $e) {
    error_log($e->getMessage());
    $pdo->rollBack();
}

22.最后,为了保持一切的模块化和可重用性,我们可以将PDO连接包装成一个单独的类Application\Database\Connection。在这里,我们通过构造函数建立一个连接。另外,还有一个静态factory()方法,让我们生成一系列的PDO实例。

namespace Application\Database;
use Exception;
use PDO;
class Connection
{
    const ERROR_UNABLE = 'ERROR: no database connection';
    public $pdo;
    public function __construct(array $config)
    {
        if (!isset($config['driver'])) {
            $message = __METHOD__ . ' : ' 
            . self::ERROR_UNABLE . PHP_EOL;
            throw new Exception($message);
        }
        $dsn = $this->makeDsn($config);        
        try {
            $this->pdo = new PDO(
                $dsn, 
                $config['user'], 
                $config['password'], 
                [PDO::ATTR_ERRMODE => $config['errmode']]);
            return TRUE;
        } catch (PDOException $e) {
            error_log($e->getMessage());
            return FALSE;
        }
    }

    public static function factory(
      $driver, $dbname, $host, $user, 
      $pwd, array $options = array())
    {
        $dsn = $this->makeDsn($config);
        
        try {
            return new PDO($dsn, $user, $pwd, $options);
        } catch (PDOException $e) {
            error_log($e->getMessage);
        }
    }

23.这个 Connection 类的一个重要组成部分是一个可以用来构造DSN的通用方法。我们需要做的就是建立PDODriver作为前缀,后面是":"。之后,我们只需从配置数组中附加键/值对。每个键/值对都用分号隔开。我们还需要把后面的分号去掉,为此使用带有负限制的substr()。

  public function makeDsn($config)
  {
    $dsn = $config['driver'] . ':';
    unset($config['driver']);
    foreach ($config as $key => $value) {
      $dsn .= $key . '=' . $value . ';';
    }
    return substr($dsn, 0, -1);
  }
}

如何运行...

首先,你可以将第一步的初始连接代码复制到 chap_05_pdo_connect_mysql.php 文件中。在这个例子中,我们假设你已经创建了一个名为 php7cookbook 的MySQL数据库,用户名为cook,密码为book。接下来,我们使用 PDO::query() 方法向数据库发送一条简单的SQL语句。最后,我们使用产生的语句对象以关联数组的形式获取结果。不要忘记用 try {} catch {} 块来包装你的代码。

<?php
$params = [
  'host' => 'localhost',
  'user' => 'test',
  'pwd'  => 'password',
  'db'   => 'php7cookbook'
];
try {
  $dsn  = sprintf('mysql:charset=UTF8;host=%s;dbname=%s',
    $params['host'], $params['db']);
  $pdo  = new PDO($dsn, $params['user'], $params['pwd']);
  $stmt = $pdo->query(
    'SELECT * FROM customer ORDER BY id LIMIT 20');
  printf('%4s | %20s | %5s | %7s' . PHP_EOL, 
    'ID', 'NAME', 'LEVEL', 'BALANCE');
  printf('%4s | %20s | %5s | %7s' . PHP_EOL, 
    '----', str_repeat('-', 20), '-----', '-------');
  while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    printf('%4d | %20s | %5s | %7.2f' . PHP_EOL, 
    $row['id'], $row['name'], $row['level'], $row['balance']);
  }
} catch (PDOException $e) {
  error_log($e->getMessage());
} catch (Throwable $e) {
  error_log($e->getMessage());
}

下面是结果输出。

在PDO构造函数中添加选项,将错误模式设置为 EXCEPTION。现在修改SQL语句,观察产生的错误信息。

$opts = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION];
$pdo  = new PDO($dsn, $params['user'], $params['pwd'], $opts);
$stmt = $pdo->query('THIS SQL STATEMENT WILL NOT WORK');

你会看到如下内容。

占位符可以是命名的,也可以是定位的。已命名的占位符在准备好的SQL语句中以冒号(:)开头,是提供给 execute() 的关联数组中作为键的引用。位置占位符在准备好的SQL语句中用问号(?)表示。

在下面的例子中,命名的占位符被用来表示WHERE子句中的值。

try {
  $dsn  = sprintf('mysql:host=%s;dbname=%s', 
                  $params['host'], $params['db']);
  $pdo  = new PDO($dsn, 
                  $params['user'], 
                  $params['pwd'], 
                  [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
  $sql  = 'SELECT * FROM customer '
      . 'WHERE balance < :val AND level = :level '
      . 'ORDER BY id LIMIT 20'; echo $sql . PHP_EOL;
  $stmt = $pdo->prepare($sql);
  $stmt->execute(['val' => 100, 'level' => 'BEG']);
  while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    printf('%4d | %20s | %5s | %5.2f' . PHP_EOL, 
      	$row['id'], $row['name'], $row['level'], $row['balance']);
  }
} catch (PDOException $e) {
  echo $e->getMessage();
} catch (Throwable $e) {
  echo $e->getMessage();
}

这个例子展示了在 INSERT 操作中使用位置占位符。请注意,作为第四个客户要插入的数据包括一个潜在的SQL注入攻击。你还会注意到,需要对正在使用的数据库的SQL语法有一定的认识。在这种情况下,MySQL的列名是用背标(')来引用的。

$fields = ['name', 'balance', 'email', 
           'password', 'status', 'level'];
$data = [
  ['Saleen',0,'saleen@test.com', 'password',0,'BEG'],
  ['Lada',55.55,'lada@test.com',   'password',0,'INT'],
  ['Tonsoi',999.99,'tongsoi@test.com','password',1,'ADV'],
  ['SQL Injection',0.00,'bad','bad',1,
   'BEG\';DELETE FROM customer;--'],
];

try {
  $dsn  = sprintf('mysql:host=%s;dbname=%s', 
    $params['host'], $params['db']);
  $pdo  = new PDO($dsn, 
                  $params['user'], 
                  $params['pwd'], 
                  [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
  $sql  = "INSERT INTO customer ('" 
   . implode("','", $fields) 
   . "') VALUES (?,?,?,?,?,?)";
  $stmt = $pdo->prepare($sql);
  foreach ($data as $row) $stmt->execute($row);
} catch (PDOException $e) {
  echo $e->getMessage();
} catch (Throwable $e) {
  echo $e->getMessage();
}

要测试使用带有命名参数的预备语句,请修改SQL语句,添加一个 WHERE 子句,检查余额小于一定金额的客户,以及级别等于 BEG、INT或ADV(即初级、中级或高级)。不使用PDO::query(),而使用PDO::prepare()。在获取结果之前,你必须执行PDOStatement::execute(),提供余额和级别的值。

$sql  = 'SELECT * FROM customer '
     . 'WHERE balance < :val AND level = :level '
     . 'ORDER BY id LIMIT 20';
$stmt = $pdo->prepare($sql);
$stmt->execute(['val' => 100, 'level' => 'BEG']);

下面是结果输出。

在调用 PDOStatement::execute()时,你可以不提供参数,而是绑定参数。这允许您将变量分配给占位符。在执行时,使用变量的当前值。

在这个例子中,我们将变量$min、$max和$level绑定到准备好的语句中。

$min   = 0;
$max   = 0;
$level = '';

try {
  $dsn  = sprintf('mysql:host=%s;dbname=%s', $params['host'], $params['db']);
  $opts = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION];
  $pdo  = new PDO($dsn, $params['user'], $params['pwd'], $opts);
  $sql  = 'SELECT * FROM customer '
      . 'WHERE balance > :min '
      . 'AND balance < :max AND level = :level '
      . 'ORDER BY id LIMIT 20';
  $stmt = $pdo->prepare($sql);
  $stmt->bindParam('min',   $min);
  $stmt->bindParam('max',   $max);
  $stmt->bindParam('level', $level);
  
  $min   =  5000;
  $max   = 10000;
  $level = 'ADV';
  $stmt->execute();
  showResults($stmt, $min, $max, $level);
  
  $min   = 0;
  $max   = 100;
  $level = 'BEG';
  $stmt->execute();
  showResults($stmt, $min, $max, $level);
  
} catch (PDOException $e) {
  echo $e->getMessage();
} catch (Throwable $e) {
  echo $e->getMessage();
}

当这些变量的值发生变化时,下一次执行将反映修改后的标准。

最佳实践

使用PDO::query()来执行一次性的数据库命令。当你需要多次处理同一条语句但使用不同的值时,使用PDO::prepare()和PDOStatement::execute()。

参考

关于不同数据库特定PDO驱动的语法和独特行为的信息,请看这篇文章。

关于PDO预定义常量的总结,包括获取模式、光标方向和属性,请看下面的文章。

上一页第五章、与数据库的交互下一页构建一个 OOP SQL 查询生成器

最后更新于4年前

http://php.net/manual/en/pdo.drivers.php
http://php.net/manual/en/pdo.constants.php