参考 — 有关 PDO 的常见问题

2022-08-30 10:11:20

这是怎麽?

这是有关 PHP 数据对象的常见问题列表

这是为什么呢?

由于PDO具有普通PHP用户所不知道的一些功能,因此有关PDO中预准备语句和错误处理的问题非常频繁。所以,这只是一个可以找到所有它们的地方。

我在这里该怎么办?

如果您的问题已与此列表一起投票,请在下面找到您的问题并将修复程序应用于您的代码。简要地看一下其他问题也是一个好主意,让自己为其他常见的陷阱做好准备。

列表

另请参见


答案 1

PDO 查询失败,但我看不到任何错误。如何从PDO获取错误消息?

为了能够看到数据库错误,必须将PDO错误设置为异常。异常在许多方面都比常规错误更好:它们总是包含堆栈跟踪,可以使用try.捕获它们。使用专用的错误处理程序捕获或处理。即使未经处理,它们也会充当常规的PHP错误,提供所有重要信息,遵循站点范围的错误报告设置。

请注意,将此模式设置为连接选项也会让 PDO 在连接错误时引发异常,这非常重要。
因此,下面是一个以正确方式创建 PDO 连接的示例:

$dsn = "mysql:host=$host;dbname=$db;charset=utf8";
$opt = array(
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    // other options 
);
$pdo = new PDO($dsn, $user, $pass, $opt);

通过这种方式连接,您将始终收到查询执行期间发生的所有数据库错误的通知。请注意,您必须能够看到一般的PHP错误。在实时站点上,您必须查看错误日志,因此,设置必须

error_reporting(E_ALL);
ini_set('display_errors',0);
ini_set('log_errors',1);

而在本地开发服务器上,可以在屏幕上出错:

error_reporting(E_ALL);
ini_set('display_errors',1);

当然,您永远不应该在PDO语句前面使用错误抑制运算符()。@

另外,由于许多不好的例子告诉你要把每个PDO语句包装成块,我必须做一个明确的说明:try..catch

不要使用尝试..catch 运算符只是为了回显错误消息。未捕获的异常对于此目的已经非常出色,因为它的行为方式与其他PHP错误相同 - 因此,您可以使用站点范围的设置来定义行为 - 因此,如果没有此无用的代码,您将收到错误消息。虽然无条件回显的错误消息可能会向潜在攻击者透露一些敏感信息,但会使诚实的访问者感到困惑。

  • 以后可以添加自定义异常处理程序,但不是必需的。特别是对于新用户,建议使用未处理的异常,因为它们非常翔实,有用且安全。
  • 仅当您要处理错误本身时才使用 - 例如,回滚事务。try..catch

答案 2

PDO 预准备语句导致 LIMIT 子句出错

出于兼容性目的,PDO 将仅通过用实际数据替换占位符来模拟预准备语句,而不是将它们单独发送到服务器,除非另有说明。对于“惰性”绑定(在 execute() 中使用数组),PDO 会将每个参数视为字符串。因此,准备好的查询将变为导致查询失败的无效语法。LIMIT ?,?LIMIT '10', '10'

这个问题可以解决

  • 通过关闭仿真模式(因为MySQL可以正确排序所有占位符):

    $conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
    
  • 通过显式绑定和设置正确的类型 (PDO::P ARAM_INT):

    $stm = $pdo->prepare('SELECT * FROM table LIMIT ?, ?');
    $stm->bindValue(1, $limit_from,PDO::PARAM_INT);
    $stm->bindValue(2, $per_page,PDO::PARAM_INT);
    $stm->execute();
    $data = $stm->fetchAll();
    

推荐