Использование плейсхолдеров в операторе LIMIT (PDO::prepare)
Как правильно использовать плейсхолдеры LIMIT?
Первый пример:
// $start_point и $offset_point динамически изменяются по ходу скрипта.
$statement = $pdo->prepare("SELECT * FROM `articles` ORDER BY `id` DESC LIMIT :start_point, :offset_point");
$statement->bindParam(":start_point", $start_point);
$statement->bindParam(":offset_point", $offset_point);
$statement->execute();
$result = $statement->fetch(PDO::FETCH_ASSOC);
var_dump($result); // Вернет false
Второй пример:
$statement = $pdo->prepare("SELECT * FROM `articles` ORDER BY `id` DESC LIMIT 0, 10");
$statement->execute();
$result = $statement->fetch(PDO::FETCH_ASSOC);
var_dump($result); // Вернет наполненный массив
Предполагаю что в первом примере, массив возвращает false, потому как плейсхолдеры указаны через запятую, но возможно я ошибаюсь. Как поступить в этой ситуации? При использовании OFFSET в LIMIT, вместо запятой, массив вернет false в обоих случаях.
Ответы (2 шт):
Нашел решение этого вопроса. При бинде значение плейсхолдера, необходимо было указать третий аргумент PDO::PARAM_INT. Вот так: $statement->bindParam(":start_point", $start_point, PDO::PARAM_INT);
Вся проблема в том что ты неправильно соединяешься с ПДО.
Во-первых, никогда не надо "предполагать". Гаданием на кофейной гуще занимаются цыганки на базаре, а не программисты. Потому что у программиста всегда есть сообщение об ошибке, в котором чётко написано, что не так. И если проблема в запятых, то тебе так и напишет, что проблема в запятых. А если в чем-то другом - то тоже напишет. В чём именно. И не нужно будет ни гадать, ни предполагать, ни фантазировать.
Поэтому при соединении надо всегда говорить ПДО, чтобы он сообщал тебе об ошибках.
Во-вторых, по умолчанию ПДО подставляет все передаваемые в запрос значения как строки. Чтобы вместо строк ПДО передавал значения отдельно от запроса, и база данных уже сама там разобралась, что ей передают, надо при соединении выключить режим эмуляции.
Поэтому код соединения берем отсюда:
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$dsn = "mysql:host=$host;dbname=$db;charset=$charset;port=$port";
try {
$pdo = new \PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
И после этого вся развесистая писанина превращается в компактный аккуратный код, который работает без ошибок, а вслучае, если все-таки произойдет ошибка по вине базы данных, то радостно о ней сообщит:
$sql = "SELECT * FROM `articles` ORDER BY `id` DESC LIMIT :start_point, :offset_point";
$statement = $pdo->prepare($sql);
$statement->execute([$start_point, $offset_point]);
$result = $statement->fetchAll();
var_dump($result);
кроме того,
В-третьих, чтобы не разводить писанину в коде, желаемый формат получаемых данных тоже можно задать при коннекте.
В-четвртых, если ты запрашиваешь в БД несклько строк, то надо использовать fetchAll, а не fetch