Как динамически связать параметры в подготовленном операторе mysqli? - PullRequest
3 голосов
/ 02 марта 2020

Я пытаюсь создать функцию для своего проекта. Я хотел бы, чтобы он обрабатывал все функции проверки. Я имею в виду, что прежде чем начать вставлять строку в базу данных, вы проверяете, существует ли строка с этим адресом электронной почты.

Чтобы использовать эту функцию динамически, она должна быть гибкой. Поэтому я поместил свои переменные в массив, но mysqli_stmt_bind_param не может обрабатывать массивы. В качестве решения я попытался сделать foreach l oop.

Запрос:

$sql = "SELECT users_id, users_email FROM users WHERE users_id = ? AND users_email = ?;";

Вызов функции:

check_database($sql, array($id, $mail), array("s", "s"), $location);

Моя исходная функция :

function check_database($sql, $variables, $types, $location)
{
    require $_SERVER['DOCUMENT_ROOT'] . '/includes/db/db.inc.php';
    $stmt = mysqli_stmt_init($conn);
    if (!mysqli_stmt_prepare($stmt, $sql)) {
        header("Location: " . $location . "?error=sqlerror");
        exit();
    } else {
        mysqli_stmt_bind_param($stmt, $types, $variables);
        mysqli_stmt_execute($stmt);
        $result = mysqli_stmt_get_result($stmt);
        if (!$row = mysqli_fetch_assoc($result)) {
            return true;
        }
    }
}

Я добавил foreach к mysqli_stmt_bind_param следующим образом:

foreach ($types as $index => $type) {
    mysqli_stmt_bind_param($stmt, $type, $variables[$index]);
}

Это дает мне ошибку, и я не знаю, как ее решить :(

Предупреждение: mysqli_stmt_bind_param (): количество переменных не соответствует количеству параметров в подготовленном выражении

1 Ответ

3 голосов
/ 02 марта 2020

Вы на правильном пути! Такая функция должна быть повседневным дополнением для каждого PHP программиста, использующего mysqli, но, как ни странно, лишь немногие когда-либо имеют идею его создания.

Однажды у меня была точно такая же идея, и я реализовал свою вспомогательную функцию mysqli :

function prepared_query($mysqli, $sql, $params, $types = "")
{
    $types = $types ?: str_repeat("s", count($params));
    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    return $stmt;
}

Основные отличия от вашего подхода

  • соединение устанавливается только один раз . Ваш код соединяется каждый раз, когда он выполняет запрос, и это абсолютно НЕ то, что он должен делать
  • его можно использовать для любого запроса, а не только для SELECT. Вы можете проверить универсальность функции в разделе примеров ниже в статье
  • типы, которые являются необязательными, поскольку большую часть времени вам не важен тип
  • no bizarre $ location. Честно говоря, все, что связано с HTTP, никогда не должно быть частью работы с базой данных! Если вам интересно, как правильно обращаться с ошибками, вот моя другая статья Отчет об ошибках в PHP

С вашим примером запроса его можно использовать так:

$check = prepared_query($sql, [$id, $mail])->get_result()->fetch_row();

или, если вам нужна отдельная функция, вы можете сделать ее также

function check_database($mysqli, $sql, $params, $types = "")
{
    return prepared_query($mysqli, $sql, $params, $types)->get_result()->fetch_row();
}

и теперь ее можно назвать

$check = check_database($sql, [$id, $mail]);
...