我该如何查看预处理语句的内容?

28

我正在学习在PHP中使用mysqli的预处理语句,通常,如果我在查询中遇到问题,我会首先将其echo到屏幕上以查看它的样子。

如何在预处理语句中执行此操作?

我想在变量被替换后查看SQL语句。

6个回答

25

使用预处理语句:

  • 当你准备好语句后,它会被发送到MySQL服务器
  • 当你绑定变量并执行语句时,只有变量被发送到MySQL服务器
  • 然后在MySQL服务器上执行语句和绑定的变量 -- 每次执行语句时不会重新“准备”(这就是为什么当多次执行同一语句时,预处理语句可以提高性能)

在PHP端没有"构建"SQL查询的过程,因此实际上无法获取该查询。

这意味着如果您想查看SQL查询,则必须使用SQL查询,而不是预处理语句。


3
好的,有点烦人=\ 你会认为应该有一种方法来获取执行的语句。 - Stomped
如果您需要在 PHP 方面进行调试,我想主要是出于调试原因,您可以“重构”与执行语句等效的 SQL 查询:您将不得不用变量的值替换占位符(当然,转义数据将由您完成);如果您经常需要这样做,您应该能够编写一个为您执行此操作的函数;否则,一些 var_dump 应该已经帮助您看到发送到 MySQL 服务器的数据了。 - Pascal MARTIN
1
@stomped 的意思是没有执行的语句。这一步被完全跳过了。 - troelskn
1
这仅适用于真正的预处理语句。但是也有模拟的预处理语句显然在PDO中是默认的 - Gumbo
你的观点是正确的,但是你可以使用“?”字符将SQL字符串与参数连接起来,并将参数放在一个字符串中,然后记录日志或显示以进行调试。请查看下面的答案... - NetVicious
我正在认真考虑放弃预处理语句。在黑暗中摸索时浪费的时间,当mysqlnd不可用时失去功能(例如get_result())等问题,似乎只为了SELECTs而值得。 - SteveCinq

13
对于使用mysql_stmt_prepare()和mysql_stmt_execute() C API函数执行的准备语句,服务器会将Prepare和Execute行写入常规查询日志中,以便您可以确定语句何时被准备和执行。
[...] 服务器会将以下行写入常规查询日志:
Prepare [1] SELECT ?
Execute [1] SELECT 3

因此,为了调试目的,请激活general log并密切关注该文件。

编辑:哦,问题有一个[mysqli]标签...完全忽略了它。
如果根本没有执行该语句,请(双重/三重)检查是否出现错误?

echo "<pre>Debug: start</pre>\n";

$mysqli = new mysqli('localhost', 'localonly', 'localonly', 'test');
if ($mysqli->connect_error) {
  die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}

$result = $mysqli->query('CREATE TEMPORARY TABLE foo (id int auto_increment, x int, primary key(id))');
if ( false=== $result) { 
 die('error : '. $mysqli->error);
}

$stmt = $mysqli->prepare('INSERT INTO foo (x) VALUES (?)');
if ( false===$stmt ) {
  die ('prepare() failed: ' . $mysqli->error);
}

$result = $stmt->bind_param('i', $x);
if ( false===$result ) {
  die('bind_param() failed');
}

$x = 1;
$result = $stmt->execute();
if ( false===$result ) {
  die('execute() failed: '.$stmt->error);
}

echo "<pre>Debug: end</pre>\n";

6

当我需要调试带参数的预处理sql时,通常会这样做。

预处理和执行的示例:

$sql = "SELECT VAL1, VAL2 FROM TABLE(?, '?', '?', '?', '?', ?, '?', '?', '?')";
$prep = ibase_prepare( $sql ) or die("Error");
$query = ibase_execute($prep, $param1, $param2, .....) or $err = true;
                              ^^^^^^^^^^^^^^^^^^^^^^^

调试语句生成的SQL的简单方法是:

printf( str_replace('?', '%s', $sql), $param1, $param2, ....);
                                      ^^^^^^^^^^^^^^^^^^^^^^

你只需要做一个printf,用准备好的SQL字符串中的 ? 替换为 %sprintf 将把所有字符解释为一个字符串,并将每个参数放置在替换的每个 %s 上。


你可以在函数中使用 PHP 的“展开”运算符(...)来使这更容易。 - kurdtpage
1
只有当参数在一个数组中时,才使用 @kurdtpage。 - NetVicious

1

我最近更新了这个项目,加入了composer集成、单元测试以及更好地处理引用参数的接受(这需要升级到php 5.6)。


我创建了一组类来扩展默认的mysqlimysqli_stmt类,以允许您查看潜在查询字符串的演示版本,这应该可以提供您所需的内容。

https://github.com/noahheck/E_mysqli

这是一个几乎可以直接替换普通mysqli对象的替代品,当您使用prepare()查询字符串时,它会返回一个自定义的mysqli_stmt对象。绑定参数后,E_mysqli将允许您查看stmt对象的新属性中生成的查询字符串:
$mysqli = new E_mysqli($dbHost, $dbUser, $dbPass, $dbName);

$query = "INSERT INTO registration SET name = ?, email = ?";

$stmt = $mysqli->prepare($query);

$stmt->bind_param("ss", $_POST['name'], $_POST['email']);

$stmt->execute();

echo $stmt->fullQuery;

会导致以下结果:

INSERT INTO registration SET name = 'John Doe', email = 'john.doe@example.com'

使用该扩展有一些注意事项(在github项目的README中有解释),但对于解决应用程序中的问题区域或从过程式转换为面向对象风格,这应该为大多数用户提供帮助。

正如我在github项目中所概述的,我没有任何使用mysqli扩展的实际经验,这个项目是应其姐妹项目用户的要求创建的,因此,任何使用该扩展的开发人员能提供的反馈将不胜感激。

免责声明 - 如我所说,我制作了该扩展。


0
赞同 Pascal MARTIN (+1) 的观点,我建议另一种调试技术:使用var_dump()或记录每个插入语句的变量,这样你就可以找出是错误数据还是逻辑上错误的 SQL 语句。

0

你可以使用像Lottip这样的工具。其思路类似于MySQL代理。它解析MySQL数据包,提取查询及其参数,因此您可以查看准备好的语句及其内容。


1
请在此改述Lottip的概念和用法。链接并非永久存在。 - atomSmasher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接