PHP: mysqli_stmt->close() 影响 stmt 的早期副本
PHP: mysqli_stmt->close() affecting earlier copy of stmt
我正在制作一个函数,以便更轻松地在 sql 查询中使用准备好的语句。但是在处理它时,我 运行 遇到了一个 st运行ge 错误。
当你 运行 $response
的第一个 var_dump
下面的代码像我期望的那样打印 $stmt
变量,但是在关闭 $stmt
之后它给出了很多的警告并打印 $stmt
的 NULL 填充版本。我只将 $stmt 复制为 $response
,所以我不希望 $response
在关闭 $stmt
时发生变化。
有人可以解释为什么会发生这种情况以及我该如何预防吗?
function sql_bug() {
global $dbc; // Database connection
$sql = "UPDATE users SET username = 'J0R1AN' WHERE id = 1"; // Test query
if ($stmt = $dbc->prepare($sql)) {
if ($stmt->execute()) {
$response = $stmt->get_result();
if ($response === false) {
// Checks for e.g. UPDATE queries that return bool(false) instead of a mysqli_result,
// and sets $response to $stmt instead, to return more valuable information when using UPDATE
$response = $stmt;
}
var_dump($response); // Prints expected $stmt variable
$stmt->close(); // Somehow changes $response?
var_dump($response); // Prints $stmt variable filled with NULLS
return $response;
}
}
return false;
}
变量赋值不会在 PHP 中创建对象的新副本。要创建副本,您需要使用 clone
。简单示例:
$obj = (object) ['a'=>42];
$new_obj = $obj;
$obj->a = 100;
var_dump($new_obj);
// outputs
// stdClass Object
// (
// [a] => 100
// )
您已成为多种谬误的受害者。
- 您不需要
close
任何东西。 PHP 会为您完成。使用 close
只会使很多事情复杂化。
- 不要检查
prepare
或 execute
函数的 return 值。而是启用 mysqli 错误报告。 How to get the error message in MySQLi?
- 不要使用全局对象或将其使用限制在绝对最低限度。
- 您不需要在函数外部公开
mysqli_stmt
或 mysqli_result
对象。执行语句并获取数据后,您可以丢弃它们。
如果我们想正确修复这个函数,我们可以这样做:
function sql_bug(\mysqli $dbc, string $sql, array $params = []): ?array {
$stmt = $dbc->prepare($sql);
if ($params) {
// bind optional parameters if the query has variable input
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
$stmt->execute();
$response = $stmt->get_result();
if ($response) {
// If the query returned results then fetch them into an array and return it
return $response->fetch_all(MYSQLI_BOTH);
}
// return nothing if the query was successfully executed and it didn't produce results
return null;
}
上述函数是一个通用函数,可以处理任何带参数和不带参数的 SQL 语句。如果查询是 INSERT 或 UPDATE,它不会 return 任何东西,如果它是 SELECT 它会 return 数组中的数据。无需复制或 return 内部对象。您正在编写一个函数来从 mysqli 内部抽象出来。
我正在制作一个函数,以便更轻松地在 sql 查询中使用准备好的语句。但是在处理它时,我 运行 遇到了一个 st运行ge 错误。
当你 运行 $response
的第一个 var_dump
下面的代码像我期望的那样打印 $stmt
变量,但是在关闭 $stmt
之后它给出了很多的警告并打印 $stmt
的 NULL 填充版本。我只将 $stmt 复制为 $response
,所以我不希望 $response
在关闭 $stmt
时发生变化。
有人可以解释为什么会发生这种情况以及我该如何预防吗?
function sql_bug() {
global $dbc; // Database connection
$sql = "UPDATE users SET username = 'J0R1AN' WHERE id = 1"; // Test query
if ($stmt = $dbc->prepare($sql)) {
if ($stmt->execute()) {
$response = $stmt->get_result();
if ($response === false) {
// Checks for e.g. UPDATE queries that return bool(false) instead of a mysqli_result,
// and sets $response to $stmt instead, to return more valuable information when using UPDATE
$response = $stmt;
}
var_dump($response); // Prints expected $stmt variable
$stmt->close(); // Somehow changes $response?
var_dump($response); // Prints $stmt variable filled with NULLS
return $response;
}
}
return false;
}
变量赋值不会在 PHP 中创建对象的新副本。要创建副本,您需要使用 clone
。简单示例:
$obj = (object) ['a'=>42];
$new_obj = $obj;
$obj->a = 100;
var_dump($new_obj);
// outputs
// stdClass Object
// (
// [a] => 100
// )
您已成为多种谬误的受害者。
- 您不需要
close
任何东西。 PHP 会为您完成。使用close
只会使很多事情复杂化。 - 不要检查
prepare
或execute
函数的 return 值。而是启用 mysqli 错误报告。 How to get the error message in MySQLi? - 不要使用全局对象或将其使用限制在绝对最低限度。
- 您不需要在函数外部公开
mysqli_stmt
或mysqli_result
对象。执行语句并获取数据后,您可以丢弃它们。
如果我们想正确修复这个函数,我们可以这样做:
function sql_bug(\mysqli $dbc, string $sql, array $params = []): ?array {
$stmt = $dbc->prepare($sql);
if ($params) {
// bind optional parameters if the query has variable input
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
$stmt->execute();
$response = $stmt->get_result();
if ($response) {
// If the query returned results then fetch them into an array and return it
return $response->fetch_all(MYSQLI_BOTH);
}
// return nothing if the query was successfully executed and it didn't produce results
return null;
}
上述函数是一个通用函数,可以处理任何带参数和不带参数的 SQL 语句。如果查询是 INSERT 或 UPDATE,它不会 return 任何东西,如果它是 SELECT 它会 return 数组中的数据。无需复制或 return 内部对象。您正在编写一个函数来从 mysqli 内部抽象出来。