我正在将mysql_*
调用更改为使用PDO调用,并且在开发新代码时无法弄清楚如何调试实际的SQL。
在mysql_*
下,我可以在PHP函数中编写一些SQL,并且可以echo
实际的SQL来查看处理器正在使用什么。
我一直无法在PDO库中找到这样的野兽。 debugDumpParams
看起来应该是,但不会吐出绑定的语句。
我遇到的问题示例:
在我的第一次尝试中,尽管绑定了data_type的字符串,但我还是绑定了一个字符串并在SQL语句中包括了引号-只是因为偶然,我才尝试从该语句中删除引号;调试会让我看到那里有重复的报价。
我将一些代码从一个项目复制到另一个项目,但无意间忘记了更正数据库名称。很自然,SQL失败了,因为这些表在另一个数据库中不存在。但是程序只是返回了正确的错误结果。在PHP日志或MySQL日志中或任何地方都没有得到任何提示,表明该表在我寻找的位置不存在。
所以,其他人如何为PDO SQL调用进行调试?我想念什么? :)
对于第一个问题,确实很难检查查询。除了在数据库服务器上记录查询外,您无能为力。原因是准备好的查询不是(总是)简单地将数据连接到查询中。重点是数据是与查询分开发送的。您可以通过$yourStatement->queryString
访问查询字符串。它只会显示带有参数的查询。
对于您的第二个问题,默认情况下,发生错误时PDO不会引发异常。由您来检查它们。您可以更改它。 http://php.net/manual/en/pdo.error-handling.php
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
然后,您可以通过围绕查询执行的try / catch块来发现问题。
几天前我遇到了同样的问题。我以这种方式解决了:
创建一个类来管理,准备和执行语句:
<?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
}
?>
希望有帮助。