Использование плейсхолдеров в операторе 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 шт):

Автор решения: KristopherRandle

Нашел решение этого вопроса. При бинде значение плейсхолдера, необходимо было указать третий аргумент 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

→ Ссылка