Вот функция, в которой я создаю соединение с БД:

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());

Когда это выполняется, я получаю следующую ошибку:

Неустранимая ошибка: Неперехваченная ошибка: вызов функции-члена fetch_assoc () с логическим значением в /opt/lampp/htdocs/src/signinscreen/repo/signin.inc.php:17 Трассировка стека: # 0 {main} добавлено в / opt / lampp / htdocs / src / signinscreen / repo / signin.inc.php в строке 17

По какой-то причине $stmt->get_result() внутри функции является фактическим object, но когда возвращается из функции, это bool.

Зачем?

1
Rey 28 Ноя 2020 в 17:02

1 ответ

Лучший ответ

Когда вы вызываете get_db_connection(), он создает новый экземпляр класса mysqli и открывает соединение с сервером 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 и передать его в качестве аргумента функциям, которым он нужен.

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()
}
3
Dharman 28 Ноя 2020 в 14:59