PHP准备语句中的嵌套准备语句

3
我正在观看一个关于使用数据库制作菜单的视频教程。与视频中使用过程化PHP不同,我尝试使用准备语句面向对象方式来完成它。但是它并没有正常工作,我无法找出原因。
代码一直运行到第17行,然后出现以下错误:
致命错误:在C:\ wamp \ www \ widget_corp \ content.php的第17行调用非对象上的bind_param()成员函数
以下是代码:
    <?php
        $query = $connection->prepare('SELECT menu_name, id FROM subjects ORDER BY position ASC;');
        $query->execute();
        $query->bind_result($menu_name, $sid);

        while ($query->fetch()){
            echo "<li>{$menu_name} {$sid}</li>";

            $query2 = $connection->prepare('SELECT menu_name FROM pages WHERE subject_id = ? ORDER BY position ASC;');
            $query2->bind_param("i", $sid); //This is line 17
            $query2->execute();
            $query2->bind_result($menu_name);
            echo "<ul class='pages'>";              
            while ($query2->fetch()){
                echo "<li>{$menu_name}</li>";
            }
            echo "</ul>";

        }
        $query->close();
    ?>

在stmt->fetch()中使用预处理语句是否不可能?

你正在使用mysqli扩展,对吧?你考虑过使用PDO吗?使用PDO,你可以将异常作为“错误处理程序”,这使你错过SQL错误的可能性更小(像在此情况下第16行最有可能导致的错误);-) - VolkerK
是的,它是mysqli,但不是SQL错误。在终端中运行SQL查询,正常工作。 - thekodols
4个回答

11

问题已解决:

在执行并绑定结果后,必须将其存储(如果要将另一个预处理语句放入提取中,则必须如此)。因此,在这种情况下,提取必须从缓冲结果中读取。

换句话说,在同一连接上进行提取操作期间无法执行另一个查询。

可行的代码:

$query = $connection->prepare("SELECT menu_name, id FROM subjects ORDER BY position ASC;");
$query->execute();
$query->bind_result($menu_name, $sid);
$query->store_result();

2
"...它必须被存储"。。真是救命稻草! - JohnA10

3
$stmt = mysqli_prepare($con,"SELECT menu_name, id FROM subjects ORDER BY position ASC");
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $menu_name, $id);
while (mysqli_stmt_fetch($stmt))
{
 $stmt2 = mysqli_prepare($con2,"SELECT menu_name FROM pages WHERE subject_id = ? ORDER BY position ASC;");
 mysqli_stmt_bind_param($stmt2,$id);
 mysqli_stmt_execute($stmt2);
 mysqli_stmt_bind_result($stmt2, $name);
 while (mysqli_stmt_fetch($stmt2))
  echo $name;
}

观察$con和$con2,您不能在使用相同连接的另一个ps中执行准备语句!!!


在这种情况下,不需要存储结果,因此您可以节省内存和时间 :) - Sourav

0

是的,您可以有多个预处理语句:预处理语句的一个想法是“准备一次,执行多次”。

  • 因此,您应该在循环外准备语句--这样它只被准备一次
  • 并在循环内执行多次。


您得到的致命错误意味着第17行的$query2不是一个对象--这意味着prepare失败了。

当其中有错误时,prepare通常会失败;您确定查询有效吗?表和列名正确吗?

prepare失败时,您应该能够使用{{link1:mysqli->error()}}或{{link2:PDO::errorInfo()}}获取错误消息。


如果我将查询语句从循环中取出来,它就可以正常工作。而“i”代表整数,这样它就知道在?的位置上放置一个整数。它没有绑定到一个名称上。 - thekodols
抱歉,我忘记了它的工作原理 :-( 我已经删除了我的回答中的这部分内容... 你尝试获取准备过程中引起的错误消息了吗? - Pascal MARTIN
如果我将内部的准备工作放到外面,它就什么也不做。没有错误,但也没有结果。除了原始的准备工作错误消息之外,我无法获得任何其他错误消息。(顺便说一句,你的响应时间非常快,非常感谢你) - thekodols
嗯,这很奇怪;也许其他人会有想法...(好吧,我也不总在SO上 - 但当我在的时候,有时会回答 :-)) - Pascal MARTIN

0

你没有说你使用哪个数据库扩展,但你似乎没有测试任何函数的返回值。不能假设数据库调用总是无缝运行。


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