使用MySQL调试PDO准备的查询

问题描述 投票:5回答:2

我正在将mysql_*调用更改为使用PDO调用,并且在开发新代码时无法弄清楚如何调试实际的SQL。

mysql_*下,我可以在PHP函数中编写一些SQL,并且可以echo实际的SQL来查看处理器正在使用什么。

我一直无法在PDO库中找到这样的野兽。 debugDumpParams看起来应该是,但不会吐出绑定的语句。

我遇到的问题示例:

  1. 在我的第一次尝试中,尽管绑定了data_type的字符串,但我还是绑定了一个字符串并在SQL语句中包括了引号-只是因为偶然,我才尝试从该语句中删除引号;调试会让我看到那里有重复的报价。

  2. 我将一些代码从一个项目复制到另一个项目,但无意间忘记了更正数据库名称。很自然,SQL失败了,因为这些表在另一个数据库中不存在。但是程序只是返回了正确的错误结果。在PHP日志或MySQL日志中或任何地方都没有得到任何提示,表明该表在我寻找的位置不存在。

所以,其他人如何为PDO SQL调用进行调试?我想念什么? :)

php mysql debugging pdo
2个回答
4
投票

对于第一个问题,确实很难检查查询。除了在数据库服务器上记录查询外,您无能为力。原因是准备好的查询不是(总是)简单地将数据连接到查询中。重点是数据是与查询分开发送的。您可以通过$yourStatement->queryString访问查询字符串。它只会显示带有参数的查询。

对于您的第二个问题,默认情况下,发生错误时PDO不会引发异常。由您来检查它们。您可以更改它。 http://php.net/manual/en/pdo.error-handling.php

$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

然后,您可以通过围绕查询执行的try / catch块来发现问题。


0
投票

几天前我遇到了同样的问题。我以这种方式解决了:

创建一个类来管理,准备和执行语句:

<?php 
class DbModelServiceMySql
{ 
  protected $driverConfig;
  protected $connection;
  protected $isconnected = FALSE;
  protected $dbname;
  public function __construct()
  {
    $this->driverConfig = $this->getDriverDef(); // to protect credentials
    if(is_array($this->driverConfig) && isset($this->driverConfig['driver'])){
        $this->_connect();
    }        
  }
  protected function getDriverDef(){
    // read private data from a protected file to create a credentials array
    // ... you must get some thing like:
    $driverConfig = ['dsn' => '...', 'username' => '...', 'password' => '...' ];
    return $driverConfig;
  }
  protected function _connect(){
    $dsn = (isset($this->driverConfig['dsn']))
       ? $this->driverConfig['dsn'] : '';
    $username = (isset($this->driverConfig['username'])) 
       ? $this->driverConfig['username'] : '';
    $password = (isset($this->driverConfig['password']))
       ? $this->driverConfig['password'] : '';
    if( ($dsn) && ($username) && ($password)){
        $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', ];
        try {
            $this->connection = new PDO($dsn, $username, $password, $options);
            $this->isconnected = TRUE;
            $this->_setdbname($dsn);
        } catch (Exception $ex) {
            throw new RuntimeException("Can't connect, bla-bla-bla..."); 
        }            
    }
    return $this->isconnected;
  }
  public function prepareAndExecute($query, $namedparams){
    if(!$this->isconnected){
      return ['error' => 'No DB connection active'];
    }
    $prepared = $this->connection->prepare($query);
    // I use named params is easiest to mantain.
    // query seems like ' ... :param1 ... :paramN ... '
    // so $namedparams = [':param1' => $value1, ..., 'paramN' => $valueN];
    $done = ( is_array($namedparams) && (count($namedparams)>0) ) 
      ? $prepared->execute($namedparams) : $prepared->execute();
      // note: it acepts no params at all.
    if($done){
      $result = $prepared->fetchAll(PDO::FETCH_ASSOC);
    }else{
      // code to debug: 
      $result =  
        'errorInfo' => $prepared->errorInfo(),
        'debugInfo' => $this->getDebugInfo()
    }
    return $result;
  }
  protected function getDebugInfo($sttmt){
    ob_start();
    $sttmt->debugDumpParams();
    $debugarr = ob_get_contents();
    ob_end_clean();
    return $debugarr;
  } 
} 
?>

我只写了必要的代码。有很多方法可以使您变得更好。

使用2行:

<?php
  $mysqlconn = new DbModelServiceMySql();
  $query = 'SELECT .... params ...';
  $keyedparams = [ ... ];
  $result = $mysqlconn->prepareAndExecute($query, $namedparams);
  if(isset($result['errorInfo'])){
    // Code to debug or dump
  }
?>

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.