覆盖持有准备好的语句的变量会关闭语句吗?

Will overriding the variable holding a prepared statement close the statement?

有些人建议在我处理完查询结果后在准备好的语句上调用 close()

我经常为准备好的语句重用相同的变量名,所以我想知道覆盖变量是否会自动调用准备好的语句上的 close()

我目前如何做的例子(SQL 是为了例子而编造的):

// Fetch the requested user
$stmt = $mysqli->prepare("SELECT * FROM user WHERE id = ?");
$stmt->bind_param("i", $_GET['userid']);
$stmt->execute();
$user = $stmt->get_result()->fetch_assoc();

// Fetch all posts associated with the user
$stmt = $mysqli->prepare("SELECT * FROM posts WHERE user_id = ?");
$stmt->bind_param("i", $user['id']);
$stmt->execute();
$result = $stmt->get_result();

$posts = array();
while ($row = $result->fetch_assoc()) {
    $posts[] = $row;
}

我应该在获取用户和获取帖子之间调用 $stmt->close(); 还是在我通过调用 $stmt = $mysqli->prepare(...); 覆盖 $stmt 时完成?

是的,大多数时候,因为PHP会尝试尽快清理没有引用的对象。这意味着一旦你覆盖它,将不再有对旧对象的引用,PHP 将清理它。部分清理 mysqli_stmt 对象涉及关闭语句。

但是有些人之所以推荐直接调用$stmt->close()是为了避免这样的错误:

mysqli_sql_exception: Commands out of sync; you can't run this command now in ...

当您尚未从 MySQL 中获取所有结果并尝试通过调用 preparequery 创建新语句时,会发生此错误。 MySQL 在获取所有剩余行之前不会让您执行任何其他操作。这通常通过 get_result()store_result() 来实现。如果您总是完整地获取结果,那么您真的不需要太担心语句何时关闭。让 PHP 为您处理。

最好的做法是避免直接使用 mysqli 函数。您应该编写一些简单的函数来封装所有 mysqli 功能,这样您就不必担心这些低级的东西。示例函数可能如下所示:

function safeQuery(\mysqli $db, string $sql, array $params = []): ?array {
    $stmt = $db->prepare($sql);
    if ($params) {
        $stmt->bind_param(str_repeat("s", count($params)), ...$params);
    }
    $stmt->execute();
    if ($result = $stmt->get_result()) {
        return $result->fetch_all(MYSQLI_BOTH);
    }
    return null;
}

$result = safeQuery($mysqli, 'SELECT * FROM user WHERE id = ?', [$_GET['userid']]);
if ($result) {
    $user = $result[0];
    $posts = safeQuery($mysqli, 'SELECT * FROM posts WHERE user_id = ?', [$user['id']]);

    foreach ($posts as $post) {
    }
}