从 PDO 预准备语句中获取原始 SQL 查询字符串
有没有办法在预准备语句上调用 PDOStatement::execute() 时执行原始 SQL 字符串?出于调试目的,这将非常有用。
有没有办法在预准备语句上调用 PDOStatement::execute() 时执行原始 SQL 字符串?出于调试目的,这将非常有用。
我假设你的意思是你想要最终的SQL查询,并将参数值插值到其中。我知道这对调试很有用,但这不是预准备语句的工作方式。参数不会与客户端上的预准备语句组合,因此 PDO 永远无权访问与其参数组合的查询字符串。
执行 prepare() 时,SQL 语句将发送到数据库服务器,执行() 时将单独发送参数。MySQL的常规查询日志确实显示了最终的SQL,并在执行()后插入了值。以下是我的一般查询日志的摘录。我从mysql CLI运行查询,而不是从PDO运行查询,但原理是相同的。
081016 16:51:28 2 Query prepare s1 from 'select * from foo where i = ?'
2 Prepare [2] select * from foo where i = ?
081016 16:51:39 2 Query set @a =1
081016 16:51:47 2 Query execute s1 using @a
2 Execute [2] select * from foo where i = 1
如果设置 PDO 属性 PDO::ATTR_EMULATE_PREPARES,也可以获得所需的内容。在此模式下,PDO 将参数插入 SQL 查询,并在执行() 时发送整个查询。这不是一个真正的预准备查询。通过在 execute() 之前将变量插入 SQL 字符串,您将规避预准备查询的好处。
来自@afilina的评论:
否,文本 SQL 查询在执行期间不会与参数组合。因此,PDO没有任何东西可以向您展示。
在内部,如果使用 PDO::ATTR_EMULATE_PREPARES,PDO 将创建 SQL 查询的副本,并在执行准备和执行之前将参数值插入其中。但 PDO 不会公开此修改后的 SQL 查询。
PDOStatement 对象具有属性$queryString,但该属性仅在 PDOStatement 的构造函数中设置,并且在使用参数重写查询时不会更新。
对于 PDO 来说,要求他们公开重写的查询将是一个合理的功能请求。但即使这样也不会给你“完整”查询,除非你使用PDO::ATTR_EMULATE_PREPARES。
这就是为什么我展示了使用MySQL服务器的常规查询日志的上述解决方法的原因,因为在这种情况下,即使是带有参数占位符的准备好的查询也会在服务器上重写,并将参数值填充到查询字符串中。但这仅在日志记录期间完成,而不是在查询执行期间完成。
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* @param string $query The sql query with parameter placeholders
* @param array $params The array of substitution parameters
* @return string The interpolated query
*/
public static function interpolateQuery($query, $params) {
$keys = array();
# build a regular expression for each parameter
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/:'.$key.'/';
} else {
$keys[] = '/[?]/';
}
}
$query = preg_replace($keys, $params, $query, 1, $count);
#trigger_error('replaced '.$count.' keys');
return $query;
}