两年前我偶然发现了this question。
有没有办法在预准备语句上调用PDOStatement :: execute()时获取原始SQL字符串?出于调试目的,这将非常有用。
获胜的回答表明
[...]你也可以得到你想要的东西 设置PDO属性 PDO :: ATTR_EMULATE_PREPARES。在这 模式,PDO将参数插入到 SQL查询并发送整个 执行()时查询。
但它没有提到如何获得生成的查询字符串。我知道这是一个糟糕的主意,但在调试模式下这并不会让我感到困扰。有人知道怎么做吗?
PS如果有某种方式我可以重新开放/引起对原来两年前主题的关注,而不是打开一个新主题,请告诉我。
答案 0 :(得分:13)
我相信在这个问题中引用的原始问题中提到了这一点。然而 实际上应该是一种检索这些数据的方法。
PDOStatement::debugDumpParams
然而,它目前没有记录在案。如果有人有兴趣投票,可以在此处http://bugs.php.net/bug.php?id=52384提交错误报告和补丁。在修复之前,您似乎只能使用查询日志记录或使用PDO :: ATTR_STATEMENT_CLASS属性设置自定义语句类。
答案 1 :(得分:2)
Afaik,PDO并没有真正向您揭露它。在开发服务器上,您可以启用MySQL的常规查询日志(如果这是您使用的),可能需要更多的sql_log_off控制,这需要SUPER权限。
答案 2 :(得分:2)
如果您无法从PDO本身获取它,请考虑使用仅用于PDOStatement::execute()
的包装类,它将记录SQL查询和值,然后在语句上调用execute()
。您将不得不重构代码以使用新类。
作为旁注,我看到PDOStatement有一个类变量$queryString
,用于保存正在使用的查询。必须从传递到execute()
或bindParam()
的任何内容中检索这些值。
首先是一些用于记录的实用程序函数:
//removes newlines and extra spaces from print_r output
function str_squeeze($str) {
if (is_array($str)) {
$str = print_r($str, true);
}
$str = preg_replace('/[(\r)?\n|\t]/', ' ', $str);
$str = trim(ereg_replace(' +', ' ', $str));
return $str;
}
function logger($str) {
//log it somewhere
}
class My_PDO_Utils {
public static function execute(PDOStatement &$stm, $values = array()) {
logger("QUERY: " . $stm->queryString . ", values = " . str_squeeze($values)) ;
return $stm->execute($values) ;
}
}
然后你的代码必须是:
$stm = $db->prepare("SELECT * FROM table2 WHERE id = ?") ;
$res = My_PDO_Utils::execute($stm, array(79)) ;
而不是
$res = $stm->execute(array(79)) ;
进一步思考它,你可以更进一步:
如果你想要冒险,可以扩展PDOStatement为你做日志记录,PDO返回扩展的PDOStatement类。这将需要尽可能少的重构,即只需将new PDO()
更改为new MY_PDO()
,但在实现中可能会变得棘手,因为您需要在MY_PDOStatement中明确定义所需的任何PDOStatement功能,以便正确调用它。
class My_PDO extends PDO {
public function prepare($sql, $options = array()) {
//do normal call
$stm = parent::prepare($sql, $options) ;
//encapsulate it in your pdostatement wrapper
$myStm = new My_PDOStatement() ;
$myStm->stm = $stm ;
return $myStm ;
}
}
class My_PDOStatement extends PDOStatement {
/**
*
* @var PDOStatement
*/
public $stm ;
public function execute($values) {
logger("QUERY: " . $this->stm->queryString . ", values = " . str_squeeze($values)) ;
return $this->stm->execute($values) ;
}
public function fetchAll($fetch_style = PDO::FETCH_BOTH, $column_index = 0, $ctor_args = array()) {
return $this->stm->fetchAll($fetch_style, $column_index, $ctor_args) ;
}
}
但现在你的代码可以是:
$db = new My_PDO($dsn, $user, $pass) ;
$stm = $db->prepare("SELECT * FROM table2 WHERE id = ?") ;
$res = $stm->execute(array(79)) ;
$row = $stm->fetchAll() ;
答案 3 :(得分:1)
在我看来,最好的方法是使用mysql日志来显示最后运行的查询,因为直接在php中获取它们是一种拖累。
从 How to show the last queries executed on MySQL?第一个回答:
此外,对于那些有MySQL> = 5.1.12:
的人SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';
看一下mysql.general_log表 如果您希望输出到文件:
SET GLOBAL log_output = "FILE"; which is set by default.
SET GLOBAL general_log_file = "/path/to/your/logfile.log"
SET GLOBAL general_log = 'ON';
我更喜欢这种方法,因为:
您没有编辑my.cnf文件,可能会永久打开日志记录 你不是在寻找查询日志的文件系统周围钓鱼 - 或者更糟糕的是,由于需要完美的目的地而分散注意力。 / var / log / var / data / log / opt / home / mysql_savior / var 重新启动服务器会使您离开原点(日志已关闭) 有关更多信息,请参阅MySQL 5.1参考手册 - 服务器系统变量 - general_log
答案 4 :(得分:0)
以下静态方法采用PDO查询模板(带有?
和/或:name
占位符的SQL查询)并插入参数:
static public function getDebugFullQuery($query, $params = array()){
if(is_array($params) && count($params)){
$search = [];
$replace = [];
foreach($params as $k => $p){
$pos = strpos($query, ":{$k}");
if($pos !== false){
$query = substr($query, 0, $pos) . "%!-!{$k}!-!%" . substr($query, $pos + strlen($k) + 1);
}
else {
$pos = strpos($query, "?");
if($pos !== false){
$query = substr($query, 0, $pos) . "%!-!{$k}!-!%" . substr($query, $pos + 1);
}
else {
break;
}
}
$search[] = "%!-!{$k}!-!%";
$replace[] = "'" . str_replace(array("\r", "\n", "'"), array("\\\\r", "\\\\n", "\\'"), $p) . "'";
}
if(count($search)){
$query = str_replace($search, $replace, $query);
}
}
return $query;
}
如方法名所示,您应该仅将其用于调试目的。