【问题标题】:Proper way to bind an array to prepared statements?将数组绑定到准备好的语句的正确方法?
【发布时间】:2026-01-28 03:55:01
【问题描述】:

这可能已经被问过好几次了,但我很难理解如何将数组绑定到 mysqli 准备好的语句。

我要做的是在消息线程中查询用户 ID 列表,然后插入到消息表中,以便通知用户有新的消息回复。

这是我尝试过的:

//now check which users are in the message thread
$stmt2 = $mysqli->prepare("SELECT DISTINCT user_id_2
FROM uc_user_messages
WHERE thread_id =  ?");
$stmt2->bind_param("i", $this->thread_id_clean);
$stmt2->bind_result($user_2_id);
$stmt2->execute();

$stmt3 = $mysqli->prepare("
INSERT INTO `users`.`uc_user_messages`(
    `id` ,
    `message_id` ,
    `user_id_2` ,
    `read` ,
    `thread_id`
    )
    VALUES (
    NULL , ?, ?, ?, ?
    );
");

//now insert the message into the user_messages table so the user can be notified of a new message
while ($row = $stmt2->fetch()){
    $stmt3->bind_param("iiii", $inserted_id, $user_2_id, $read, $this->thread_id_clean );
    $stmt3->execute();
}   

我做错了什么?我也尝试将准备好的语句放入循环中,但我不断收到此错误:

致命错误:在非对象上调用成员函数 bind_param()

我还使用测试数据手动运行了查询,所以我知道是循环导致值无法正确绑定。

编辑:我应该补充一点,选择查询工作正常,并且是插入查询导致错误。

【问题讨论】:

  • 您的意思是SELECT 有效而INSERT 无效?
  • 是的。我只是不知道如何绑定上一个查询中的 $user_2_id 变量。我还尝试打印出我绑定到查询的每个值,所有结果都符合预期。
  • 很少使用mysqli_,但mysqli_error() 可能会告诉你一些事情。但是,你知道you can just do this in 1 query 吗? INSERT INTO uc_user_messages SELECT DISTINCT NULL, ?, user_id, ?, ? FROM uc_user_messages WHERE ....
  • Fatal error: Call to a member function bind_param() on a non-object 让我认为prepare$stmt3 失败。

标签: php mysql mysqli


【解决方案1】:

致命错误:在非对象上调用成员函数 bind_param()

这意味着 $stmt2 或 $stmt3 不是对象。如果解析或验证查询有任何问题,prepare() 函数将返回 false。但是false->bind_param() 是行不通的。

这是许多 MySQL 开发人员常犯的错误。解决方案是您必须检查 prepare() 是否返回成功,而不是 false

例子:

$stmt2 = $mysqli->prepare("...");
if ($stmt2 === false) {
  // do something to report $mysqli->error, and return
}

另见http://php.net/manual/en/mysqli.error.php

【讨论】:

    【解决方案2】:

    一旦 var 绑定到您的 prep 语句,它就会保持绑定状态。

    这意味着 cou 只调用一次 bind_param(在循环之外),然后只需重复两步循环“更改 var 值/执行”。

    php.net: Check section #3 INSERT prepared once, executed multiple times

    还要确保用于 db 和表名的引号不会干扰 PHP backtick operator.(在这种特定情况下,您可以省略这些引号。)

    【讨论】:

      【解决方案3】:
      1. 您没有检查错误。按照此处说明的方式进行操作:https://*.com/a/15447204/285587
      2. 该错误很可能是“命令不同步”之类的错误。您必须在第一个查询中使用 store_result() 以避免这种情况。奇怪的是,Bill 有一个perfect answer which is first on google search - 您可以参考它了解详细信息。

      我只是不知道你说的是哪个数组。

      【讨论】: