【问题标题】:Handling PDO and Statement Exceptions处理 PDO 和语句异常
【发布时间】:2015-12-09 15:46:16
【问题描述】:

我们一直在检查我们的一些旧代码,我们发现了一些看起来像这样的代码:

try
{
    $stmt = $db->prepare($query);
    $stmt->bindvalue(1, $id, PDO:ARAM_INT);
    $stmt->execute();
    $row = $stmt->fetchColumn();
}
catch(PDOException $e)
{
    echo "There was an issue with query: ";
    print_r($db->errorInfo());
}

乍一看我们认为看起来不错(甚至 Stack Exchange 上的许多答案都将其作为示例代码)。然后我们查看了 errorInfo 函数的 PHP 文档,它指出:

PDO::errorInfo() 仅检索直接在 数据库句柄。如果您通过创建 PDOStatement 对象 PDO:repare() 或 PDO::query() 并在语句上调用错误 句柄,PDO::errorInfo() 不会反映语句中的错误 处理

如果我们理解正确,这意味着如果我们执行的任何语句操作出现任何问题,我们实际上不会在“查询出现问题:”之后打印出我们期望的错误代码。这是正确的吗?

鉴于此,我们开始寻找正确的方法来执行此操作,我们首先查看 PDOException 类文档,该文档表明我们可能会执行以下操作:

try
{
    $stmt = $db->prepare($query);
    $stmt->bindvalue(1, $id, PDO:ARAM_INT);
    $stmt->execute();
    $row = $stmt->fetchColumn();
}
catch(PDOException $e)
{
    echo "There was an issue with query: ";
    print_r($e->errorInfo());
}

我的问题是:

  1. 上述方法是否正确?如果不是,那么正确的做法是什么?
  2. 除了您可以从 PDOException 中看到的信息之外,是否还有其他有用的信息可以通过使用 $db->e​​rrorInfo() 和 $db->e​​rrorCode(或 $stmt->errorInfo 和 $stmt->errorCode)获得?
  3. 如果从这些详细的调用中有更详细的可用和有用的信息,那么有没有办法通过检查 PDOException 来区分它是由 PDO 引发还是由 PDOStatement 引发的?

【问题讨论】:

    标签: php pdo


    【解决方案1】:

    $db->prepare 或任何$stmt 操作都可能引发异常。你不知道错误从何而来,所以你不应该猜测。异常本身包含有关问题所在的所有信息,所以是的,咨询它,只有它是唯一明智的做法。

    此外,在数据库调用周围直接try..catch 通常是无稽之谈(除非您有一个明确的计划,如果这个特定的数据库操作失败,您想做什么)。在您的示例中,您只是输出错误并继续,就好像什么都没发生一样。这不是明智的错误处理。在出现严重错误的情况下明确存在异常中止和跳转,这意味着您的代码部分实际上应该是 catching 异常应该存在多个层,并且无法访问 $db$stmt at全部(因为它在不同的范围内)。也许您根本不应该捕获异常并让它终止您的整个脚本(同样,除非您预计会发生错误并且有明确的计划如何处理它以及如何将您的应用程序恢复到已知状态)。因此,再一次,仅查看异常本身中的信息是唯一明智的做法。

    如果从这些详细的调用中有任何更详细的可用和有用的东西,那么有没有办法通过检查 PDOException 来区分它是由 PDO 抛出还是由 PDOStatement 抛出的?

    这仅在再次您有任何类型的恢复计划并且该计划因错误发生的位置而异时才有用。首先,我对此表示怀疑,但如果确实如此,那么你会这样做:

    try {
        $stmt = $db->prepare($query);
    } catch (PDOException $e) {
        // do something to save the day
    }
    
    try {
        $stmt->bindValue(...)
        ..
    } catch (PDOException $e) {
        // save the day another way
    }
    

    换句话说,您将try..catch 语句隔离到您想要区分的代码的较小部分。但是,真的……如果$db->prepare 失败了,你会怎么做?无论哪种方式,您都无法继续使用其余代码。如果$stmt 方法失败,您将采取什么不同方式?作为一个原子单位,您无法查询数据库,句号。

    PDOException::$code 将为您提供更详细的 SQLState 错误代码,它可能会告诉您一些有用的信息(例如,违反唯一约束),这是有时可以使用的有用信息。但是在检查时,哪个特定行引发了错误是无关紧要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-29
      • 2014-11-01
      • 2012-01-07
      • 2017-01-07
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      相关资源
      最近更新 更多