如何在 mysqli 准备语句中动态绑定参数?

How to dynamically bind params in mysqli prepared statement?

我正在尝试为我的项目创建一个函数。我希望它能处理所有检查功能。我的意思是,在您开始在数据库中插入行之前,您检查是否存在包含该电子邮件地址的行。

要动态使用此功能,它需要灵活。所以我确实把我的变量放在一个数组中,但是 mysqli_stmt_bind_param 不能处理数组。作为解决方案,我尝试制作一个 foreach 循环。

查询:

$sql = "SELECT users_id, users_email FROM users WHERE users_id = ? AND users_email = ?;";

调用函数:

check_database($sql, array($id, $mail), array("s", "s"), $location);

我的原函数:

function check_database($sql, $variables, $types, $location)
{
    require $_SERVER['DOCUMENT_ROOT'] . '/includes/db/db.inc.php';
    $stmt = mysqli_stmt_init($conn);
    if (!mysqli_stmt_prepare($stmt, $sql)) {
        header("Location: " . $location . "?error=sqlerror");
        exit();
    } else {
        mysqli_stmt_bind_param($stmt, $types, $variables);
        mysqli_stmt_execute($stmt);
        $result = mysqli_stmt_get_result($stmt);
        if (!$row = mysqli_fetch_assoc($result)) {
            return true;
        }
    }
}

我在 mysqli_stmt_bind_param 中添加了一个 foreach,如下所示:

foreach ($types as $index => $type) {
    mysqli_stmt_bind_param($stmt, $type, $variables[$index]);
}

这给了我一个错误,我不知道如何解决:(

Warning: mysqli_stmt_bind_param(): Number of variables doesn't match number of parameters in prepared statement

您的方向非常正确!这样的功能应该是每个 PHP 使用 mysqli 的程序员的日常伴侣,但奇怪的是,只有少数人有创建一个的想法。

我曾经有过完全相同的想法并实现了我自己的 mysqli helper function

function prepared_query($mysqli, $sql, $params, $types = "")
{
    $types = $types ?: str_repeat("s", count($params));
    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    return $stmt;
}

与您的方法的主要区别

  • 连接仅一次。您的代码每次执行查询时都会连接,这绝对不是它应该做的
  • 它可以用于任何查询,而不仅仅是 SELECT。您可以在文章
  • 下方的示例部分检查函数的多功能性
  • 类型是可选的,因为大多数时候你不关心类型
  • 没有奇怪的 $location 变量。老实说,任何 HTTP 内容都不应该成为数据库操作的一部分!如果你好奇如何正确处理错误,这里是我的另一篇文章Error reporting in PHP

对于您的示例查询,它可以像这样使用

$check = prepared_query($sql, [$id, $mail])->get_result()->fetch_row();

或者,如果你想要一个独特的功能,你也可以做到

function check_database($mysqli, $sql, $params, $types = "")
{
    return prepared_query($mysqli, $sql, $params, $types)->get_result()->fetch_row();
}

现在可以称呼为

$check = check_database($sql, [$id, $mail]);