可移植脚本的另一个难题是处理从各种数据库处理程序返回的各种不同的错误消息;某些数据库对于程序化处理错误的支持能力很差,而其他一些数据库则具有非常丰富的错误代码。只要可行,PDO 将为您的脚本提供一个统一的错误代码,从而使您不必为应对可移植性的这个方面所累。当然,PDO 还会为驱动程序提供原生错误代码和错误消息,以防您需要用它来进行诊断,或者错误代码映射不完整。
另一个困扰 PHP 数据库扩展的一致性问题是错误处理策略的一致性:某些扩展会返回的错误代码需要您手动抓取错误字符串,而其他一些扩展则只是发出 PHP 警告。PDO 允许您从下列三种不同的错误处理策略中选择一种:
·PDO_ERRMODE_SILENT
这是默认模式;它只是使用语句和数据库句柄对象的 errorCode() 和 errorInfo() 方法为您设置要检查的错误代码。
if (!$dbh->exec($sql)) {
echo $dbh->errorCode() ."<BR>";
$info = $dbh->errorInfo();
// $info[0] == $dbh->errorCode() 统一的错误代码
// $info[1] 是驱动程序特定的错误代码
// $info[2] 是驱动程序特定的错误字符串
}
·
PDO_ERRMODE_WARNING
除了设置错误代码之外,PDO 还会发出 PHP 警告,您可以使用常规的 PHP 错误处理程序捕获该警告,并集中应用您准备好用于应用程序的任何错误处理/记录策略,或者只是使该错误显示在浏览器中(在内部测试过程中非常有用)。
·
PDO_ERRMODE_EXCEPTION
除了设置错误代码之外,PDO 还会抛出一个 PDOException,并将其属性设置为包含该错误代码和信息。然后,您可以在代码的较高级别捕获该异常,使用全局异常处理程序捕获该异常,或者不对其进行处理而终止脚本(此时将回滚任何未决的事务)。
try {
$dbh->exec($sql);
} catch (PDOException $e) {
// 显示警告消息
print $e->getMessage();
$info = $e->errorInfo;
// $info[0] == $e->code; unified error code
// $info[1] 是驱动程序特定的错误代码
// $info[2] 是驱动程序特定的错误字符串
}
请注意,与警告或异常相比,静默模式针对运行时错误使用的资源最少,但是为了获得该速度,您牺牲了一些简单性,而变得有一点复杂。
统一错误代码表当前包括下列常量: PDO_ERR_NONE、PDO_ERR_CANT_MAP、PDO_ERR_SYNTAX、PDO_ERR_CONSTRAINT、PDO_ERR_NOT_FOUND、PDO_ERR_ALREADY_EXISTS、PDO_ERR_NOT_IMPLEMENTED、PDO_ERR_MISMATCH、PDO_ERR_TRUNCATED、PDO_ERR_DISCONNECTED。
这些常量所代表的意思字面即可推知,但是 PDO_ERR_CANT_MAP 代码除外;这是一个 PDO 特定的代码,也就是说它无法将驱动程序特定的代码映射到统一的错误代码,因此您应该查询 errorInfo() 方法返回的驱动程序特定代码来获得更多信息。
数据类型
PDO 在某种程度上类型不可知,因此它喜欢将数据表示为字符串,而不是将其转换为整数或双精度类型。此时您可能对此有些迷惑,但是原因非常简单:字符串类型是最精确的类型,在 PHP 中具有最广泛的应用范围;过早地将数据转换为整数或者双精度类型可能会导致截断或舍入错误。通过将数据以字符串抽出,PDO 为您提供了一些脚本控制,您可以使用普通的 PHP 类型转换工具(如数学运算过程中的转换和隐式)来控制如何进行转换以及何时进行转换。
NULL
如果结果集中的某列包含一个 NULL 值,PDO 则会将其映射为 PHP null 值。Oracle 在将数据返回 PDO 时会将空字符串转换为 NULL,但是 PHP 支持的任何其他数据库都不会这样处理,从而导致了可移植性问题。PDO 提供了一个驱动程序级属性 PDO_ATTR_ORACLE_NULLS,该属性会为其他数据驱动程序模拟此行为:
$dbh = new PDO('OCI:', 'scott', 'tiger');
$dbh->setAttribute(PDO_ATTR_ORACLE_NULLS, true);
// 现在从此 $dbh 打开的任何语句中的
// 空字符串都将被转换为 NULL
POD 的现状和未来
PDO 现在仍相当不成熟,但是会快速成熟起来。在编写本文之时,我在本文中提到的任何内容都能够通过 PDO_OCI 驱动程序适用于 Oracle 8 或更高版本(在 Oracle 8.0 和 9.2 上测试过)。
已经计划增加以下主要特性,在不久将可以使用: