如何在 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]);
我正在尝试为我的项目创建一个函数。我希望它能处理所有检查功能。我的意思是,在您开始在数据库中插入行之前,您检查是否存在包含该电子邮件地址的行。
要动态使用此功能,它需要灵活。所以我确实把我的变量放在一个数组中,但是 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]);