Закрытие подготовленных заявлений - PullRequest
3 голосов
/ 20 апреля 2020

Я знаю, что закрытие подготовленных операторов рекомендуемая вещь .

Но у меня есть сценарий 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

или лучше закрыть готовые заявления сразу после того, как я их использую, чтобы избежать каких-либо ошибок?

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Не закрывайте его.

Несмотря на то, что говорит другой ответ (написано 10 лет go), как правило, вы не закрываете подготовленное утверждение. Это просто не нужно. Это будет закрыто автоматически когда будет закрыта текущая область. Это означает, что вам не нужно закрывать оператор даже во время выполнения скрипта, не говоря уже о завершении скрипта PHP полностью - в этом случае все соединение с базой данных будет автоматически закрыто и освободится все связанные ресурсы, а также.

Кстати, вы пишете почти в пять раз больше кода для выполнения простого запроса, чем нужно. Вот как это должно быть сделано, аккуратно и кратко:

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

Дело в том, что код вашей базы данных никогда не должен сообщать о своих ошибках. В другом месте должна быть отдельная часть вашего кода, которая позаботится обо всех ошибках.

И нет, выполнение перенаправления HTTP в случае ошибки приложения не является способом go. Ваше приложение должно просто вернуть правильный код HTTP (5xx), чтобы сообщить клиенту, что возникла проблема.

1 голос
/ 20 апреля 2020

Проблема с вашим кодом не в использовании close(), а в сообщении об ошибке, которое не включено. Вы должны включить mysqli, сообщение об ошибке , и тогда вы можете упростить свой код.

Ваши операции с БД в идеале должны быть заключены в функцию или метод, и тогда вам не нужно беспокоиться о закрытии чего-либо. Он будет закрыт для вас автоматически.

$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);
}

Тогда, если у вас есть исключение, вы должны создать generi c обработчик ошибок, который перенаправит пользователя на страницу 500, сгенерировав код ответа HTTP 500 при возникновении ошибки, и запишет все подробности исключения в файл на сервере.

...