【问题标题】:Is there any way to get sql statement from PDOException?有什么方法可以从 PDOException 获取 sql 语句?
【发布时间】:2018-04-21 13:54:18
【问题描述】:

我会发现在捕获它时获取导致PDOException 的 sql 语句文本很有用。 据我研究,异常没有该信息。 例如(在阅读了PDOException 类的文档之后),我使用了Exception::__toString() 并得到了类似的东西:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '14' for key 'PRIMARY'
exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '14' for key 'PRIMARY'' in xx.php:64
Stack trace:
#0 xx.php(64): PDOStatement->execute(Array)
#1 xx.php(108): insertKeplerian(Object(MyConn), '14', Object(stdClass))
#2 Command line code(1): include('/srv/www/htdocs...')
#3 {main}

问题是我有从不同函数执行的语句,我想在单个 catch 块中捕获所有异常。 如果确实无法从异常中恢复语句,那么我可以想到两种可能的解决方案:

  1. 将 sql 语句文本存储在某种“全局”变量中 可以在catch 部分恢复。
  2. 在每个执行 SQL 语句的函数中捕获和管理PDOException

我想有更好的方法来做到这一点。

【问题讨论】:

  • 恐怕您将不得不构建自己的查询监视器。请参阅this StackOverflow answer 了解更多信息。
  • 这并不重要,因为有了堆栈跟踪,您只需单击几下即可导航到问题查询。但无论如何: 3. 创建一个数据库包装器,它会为您运行查询,并在里面有一个 try-catch。

标签: php pdo


【解决方案1】:

我根据答案https://stackoverflow.com/a/7716896/4044001 找到了执行此操作的方法。 代码如下,其中包括对参数标记支持问号 (?) 而不是命名占位符 (:name) 的改进:

<?php
///\brief Class that extends PDOStatement to add exception handling
class MyPDOStatement extends PDOStatement
{
   protected $_debugValues = null;
   protected $_ValuePos = 0;

   protected function __construct()
   {
      // need this empty construct()!
   }

   ///\brief overrides execute saving array of values and catching exception with error logging
   public function execute($values = array())
   {
      $this->_debugValues = $values;
      $this->_ValuePos    = 0;

      try {
         $t = parent::execute($values);
      }
      catch (PDOException $e) {
         // Do some logging here
         print $this->_debugQuery() . PHP_EOL;
         throw $e;
      }

      return $t;
   }

   ///\brief Retrieves query text with values for placeholders
   public function _debugQuery($replaced = true)
   {
      $q = $this->queryString;

      if (!$replaced) {
         return $q;
      }

      return preg_replace_callback('/(:([0-9a-z_]+)|(\?))/i', array(
         $this,
         '_debugReplace'
      ), $q);
   }

   ///\brief Replaces a placeholder with the corresponding value
   //$m is the name of a placeholder
   protected function _debugReplace($m)
   {
      if ($m[1] == '?') {
         $v = $this->_debugValues[$this->_ValuePos++];
      }
      else {
         $v = $this->_debugValues[$m[1]];
      }
      if ($v === null) {
         return "NULL";
      }
      if (!is_numeric($v)) {
         $v = str_replace("'", "''", $v);
      }

      return "'" . $v . "'";
   }
}

///\brief Class that encapsulates DB connection parameters and configuration
class MyConn extends PDO
{
   function __construct()
   {
      $servername = "localhost";
      $username   = "root";
      $password   = "xxx";
      $dbname     = "new_att";

      parent::__construct("mysql:host=$servername;dbname=$dbname", $username, $password);

      //Set connection to raise exception when error
      $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      //Set connection to use the derived class MyPDOStatement instead of PDOStatement for statements
      $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array(
         'MyPDOStatement',
         array()
      ));
   }
}
?>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 2020-04-11
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 2012-02-19
    • 2014-01-23
    相关资源
    最近更新 更多