【问题标题】:Closing prepared statements关闭准备好的语句
【发布时间】:2020-04-20 13:15:25
【问题描述】:

我知道结束准备好的语句是a suggested thing to do。

但我有一个像这样的 PHP 脚本:

$sql = "SELECT * FROM `mytable` WHERE ...";
$stmt = $dbh->stmt_init();

if($stmt->prepare($sql))
{
    $stmt->bind_param("s", $user);

    if($stmt->execute())
    {
        $result = $stmt->get_result();
        $stmt->close();
    } else
        header("Location: .?error=unknown");
} else
    header("Location: .?error=conn");

如果一切正常,该语句将关闭,但在执行过程中发生故障时,它不会关闭。

我应该写吗

else {
    $stmt->close();
    header("Location: .?error=unknown");
}

和

else {
    $stmt->close();
    header("Location: .?error=conn");
}

或者,既然发生了错误,我不应该担心关闭语句?

或者我什至可以写:

$sql = "SELECT * FROM `mytable` WHERE ...";
$stmt = $dbh->stmt_init();

if($stmt->prepare($sql))
{
    $stmt->bind_param("s", $user);

    if($stmt->execute())
    {
        $result = $stmt->get_result();
    } else
        header("Location: .?error=unknown");
} else
    header("Location: .?error=conn");

/*some other code*/

$stmt->close; //close every statement at the very end of the script

还是在我使用完准备好的语句后立即关闭它们以避免任何类型的错误更好?

【问题讨论】:

  • PHP 有一个垃圾回收器,它将在脚本结束时被释放。但是当你不再需要它时,你应该关闭它。
  • 你应该使用 exit();在每次标头调用之后,停止脚本的处理。
  • @JayBlanchard 我知道,这只是一个Minimal Reproducible Example
  • @MarkusZeller 所以我应该选择第二个选项吗? (每次重定向前关闭)
  • 我肯定更喜欢那个。但如前所述,PHP 将在退出时自行清理。

标签: php mysqli header prepared-statement


【解决方案1】:

你的代码的问题不是close()的使用,而是报错,没有开启。您必须启用mysqli error reporting,然后才能简化您的代码。

理想情况下,您的数据库操作应该封装在一个函数或方法中,这样您就不必担心关闭任何内容。它将自动为您关闭。

$sql = "SELECT * FROM `mytable` WHERE ...";
$stmt = $dbh->prepare($sql);
$stmt->bind_param("s", $user);
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();

如果你要将它包装在一个函数中,那么就不需要close()。

function getResults(\mysqli $dbh, string $sql, string $types, array $params): array {
    $stmt = $dbh->prepare($sql);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
}

然后,如果您有异常,您应该创建一个通用错误处理程序,当错误发生时,它将通过生成 HTTP 500 响应代码将用户重定向到 500 页面,并将记录所有异常详细信息到服务器上的一个文件中。

【讨论】:

  • 谢谢...函数是否实现了垃圾回收(包括$stmt->close()返回值时?
  • mysqli_stmt 将在对它的所有引用消失后调用析构函数。当您将变量限制在函数范围内时,您可以确保对象仅在您需要时才存在。然后 PHP 将把它全部清理干净。即使没有,也几乎没有任何理由自己关闭声明。当脚本执行结束时,所有对象都将消失。我自己从不在任何代码中使用close()。
  • @Foxel 如果您要从函数返回 $stmt,则唯一例外。在这种情况下它不会关闭
  • @YourCommonSense 根据 Dharman 所说,在您退出函数范围后,PHP 会对其中的所有内容应用垃圾收集......所以我认为即使我从函数返回语句
  • @Foxel 当然这不是问题。如果退回它就不会关闭 - 仅此而已
【解决方案2】:

不要关闭它。

尽管其他答案(写于 10 年前)说了什么,但通常您不会关闭准备好的陈述。只是没有必要。当前作用域关闭时会自动关闭。这意味着即使在脚本执行期间您也不关心关闭语句,更不用说完全完成 PHP 脚本 - 在这种情况下,整个数据库连接将自动关闭,它会释放所有相关的资源也是如此。

顺便说一句,运行简单查询所需的代码几乎是所需的五倍。以下是它应该如何完成,整洁和简洁:

$sql = "SELECT * FROM `mytable` WHERE ...";
$stmt->prepare($sql);
$stmt->bind_param("s", $user);
$stmt->execute();
$result = $stmt->get_result();

问题是,您的数据库代码永远不应该报告它的错误。其他地方的代码应该有一个不同的部分,可以处理所有错误。

不,在应用程序错误的情况下执行 HTTP 重定向不是要走的路。您的应用程序应该只返回一个正确的 HTTP 代码 (5xx) 来告诉客户端有问题。

【讨论】:

  • 是的,这是要走的路。并设置异常处理程序。您可以在我的article 中找到完整的示例
猜你喜欢
  • 2011-10-01
  • 1970-01-01
  • 2014-04-17
  • 1970-01-01
  • 1970-01-01
  • 2014-09-16
  • 2014-04-11
  • 2012-06-07
  • 2016-02-24
相关资源
最近更新 更多