从函数返回的 $stmt 与函数内部不同

$stmt returned from function is different than inside the function

这是我创建数据库连接的函数:

function get_db_connection()
{
    $host = "127.0.0.1:3306";
    $username = "root";
    $password = "";
    $db = "crm";

    return mysqli_connect($host, $username, $password, $db);
}

这是我使用查询的函数:

function query_user_by_username($username)
{
    $conn = get_db_connection();

    $stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
    $stmt->bind_param("s", $username);
    $stmt->execute();
    //var_dump($stmt->get_result()->fetch_assoc());

    return $stmt;
}

当我在函数内部执行 var_dump 时,我得到 NULL,这对于当前情况来说是非常好的响应。

但是,当我从另一个地方调用这个函数时,在执行相同的 var_dump.

时出现错误

示例代码:

require_once(__DIR__ . '/../../db/dbh.inc.php');

$db_response = query_user_by_username("zxc");
var_dump($db_response->get_result()->fetch_assoc());

执行此操作时,出现以下错误:

Fatal error: Uncaught Error: Call to a member function fetch_assoc() on boolean in /opt/lampp/htdocs/src/signinscreen/repo/signin.inc.php:17 Stack trace: #0 {main} thrown in /opt/lampp/htdocs/src/signinscreen/repo/signin.inc.php on line 17

出于某种原因,函数内部的 $stmt->get_result() 是一个实际的 object 但当从函数返回时,它是 bool.

为什么?

当您调用 get_db_connection() 时,它会创建一个新的 mysqli 实例 class 并打开与 MySQL 服务器的连接。只要您有一个指向它的 PHP 变量,这个对象就会存在。在您的情况下,连接仅在 query_user_by_username() 函数的范围内有效。

mysqli 中的准备语句默认生成无缓冲的结果。结果不会自动从 MySQL 服务器获取,您需要调用 get_result()store_result() 或逐行获取它们。要从服务器获取结果集,连接必须打开。

当您离开 query_user_by_username() 函数时,PHP 将关闭连接并丢弃所有剩余结果。当您尝试在函数外部使用 get_result() 获取结果集时,由于连接已关闭,因此没有可获取的结果。

要解决此问题,您应该将 mysqli 连接作为参数传递给函数。

function query_user_by_username(mysqli $conn, $username)
{
    $stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
    $stmt->bind_param("s", $username);
    $stmt->execute();

    return $stmt;
}

那么您应该确保只要您的代码需要,连接就会一直存在。实际上,这意味着您应该只创建一个 mysqli 实例 class 并将其作为参数传递给需要它的函数。

require_once(__DIR__ . '/../../db/dbh.inc.php');
$conn = get_db_connection();

$db_response = query_user_by_username($conn, "zxc");
var_dump($db_response->get_result()->fetch_assoc());

如您所见,mysqli 是一个低级 API,这使得处理数据库操作变得困难。因此,最好使用 PDO。如果您希望继续使用 mysqli,那么您可以考虑编写一个 或以一种永远不会将底层 mysqli 函数暴露给您的业务层的方式编写您的函数。例如:

function query_user_by_username(mysqli $conn, $username): ?array
{
    $stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
    $stmt->bind_param("s", $username);
    $stmt->execute();

    // only return the data, not the mysqli object
    return $stmt->get_result()->fetch_assoc()
}