Справка - часто задаваемые вопросы о PDO
Что это?
Это список часто задаваемых вопросов, касающихся объектов данных PHP
Почему это?
Поскольку PDO имеет некоторые функции, неизвестные обычному пользователю PHP, вопросы относительно подготовленных операторов и обработки ошибок в PDO довольно часты. Так что это просто место, где можно найти все их.
Что мне здесь делать?
Если ваш вопрос был закрыт с этим списком, найдите его ниже и примените исправление к своему коду. Это также хорошая идея, чтобы кратко взглянуть на другие вопросы, чтобы подготовиться к другим распространенным ловушкам.
Список
- Запрос PDO не выполнен, но я не вижу никаких ошибок. Как получить сообщение об ошибке от PDO?
- Как я могу использовать подготовленные заявления с оператором LIKE?
- Как создать подготовленный оператор для оператора IN ()?
- Могу ли я использовать подготовленный оператор PDO для привязки идентификатора (таблицы или имени поля) или синтаксического ключевого слова?
- Подготовленный оператор PDO вызывает ошибку в операторе LIMIT
Смотрите также
3 ответа
Запрос PDO не выполнен, но я не вижу никаких ошибок. Как получить сообщение об ошибке от PDO?
Чтобы иметь возможность видеть ошибки базы данных, необходимо установить для errmode PDO исключения. Исключения лучше обычных ошибок во многих отношениях: они всегда содержат трассировку стека, их можно перехватить с помощью try..catch или обработать с помощью специального обработчика ошибок. И даже необработанные, они действуют как обычные ошибки PHP, предоставляя всю важную информацию, следуя настройкам отчетов об ошибках по всему сайту.
Обратите внимание, что установка этого режима в качестве параметра подключения позволит PDO также генерировать исключения при ошибках подключения, что очень важно.
Итак, вот пример для правильного создания соединения PDO:
$dsn = "mysql:host=$host;dbname=$db;charset=utf8";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// other options
);
$pdo = new PDO($dsn, $user, $pass, $opt);
Подключившись таким образом, вы всегда будете уведомлены обо всех ошибках базы данных, произошедших во время выполнения запроса. Обратите внимание, что вы должны иметь возможность видеть ошибки PHP в целом. На живом сайте вы должны заглянуть в журналы ошибок, поэтому настройки должны быть
error_reporting(E_ALL);
ini_set('display_errors',0);
ini_set('log_errors',1);
в то время как на локальном сервере разработки нормально делать ошибки на экране:
error_reporting(E_ALL);
ini_set('display_errors',1);
и, конечно, вы никогда не должны использовать оператор подавления ошибок (@
) перед вашими заявлениями PDO.
Кроме того, из-за многих плохих примеров, говорящих вам обернуть каждый оператор PDO в try..catch
блок, я должен сделать четкое примечание:
НЕ используйте оператор try..catch только для вывода сообщения об ошибке. Uncaught исключение уже отлично подходит для этой цели, так как оно будет действовать точно так же, как и другие ошибки PHP - так что вы можете определить поведение, используя настройки всего сайта - так что вы получите сообщение об ошибке без этого бесполезного кода. Хотя безоговорочно отображаемое сообщение об ошибке может раскрыть некоторую конфиденциальную информацию потенциальному злоумышленнику, все же запутать честного посетителя.
- Пользовательский обработчик исключений может быть добавлен позже, но не обязательно. Специально для новых пользователей рекомендуется использовать необработанные исключения, так как они чрезвычайно информативны, полезны и безопасны.
- использование
try..catch
только если вы собираетесь обработать саму ошибку - скажем, откатить транзакцию.
Подготовленный оператор PDO вызывает ошибку в предложении LIMIT
В целях совместимости PDO будет просто эмулировать подготовленные операторы, заменяя заполнители фактическими данными, а не отправлять их на сервер отдельно, если не указано иное. А с "ленивым" связыванием (используя массив в execute()), PDO будет обрабатывать каждый параметр как строку. В результате подготовленный LIMIT ?,?
запрос становится LIMIT '10', '10'
который является недопустимым синтаксисом, который приводит к сбою запроса.
Эта проблема может быть решена либо
отключив режим эмуляции (поскольку MySQL может правильно сортировать все заполнители):
$conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
путем привязки и установки правильного типа (PDO::PARAM_INT) явно:
$stm = $pdo->prepare('SELECT * FROM table LIMIT ?, ?'); $stm->bindValue(1, $limit_from,PDO::PARAM_INT); $stm->bindValue(2, $per_page,PDO::PARAM_INT); $stm->execute(); $data = $stm->fetchAll();
Как я могу использовать подготовленные заявления с оператором LIKE?
Подготовленный оператор может представлять только полный литерал данных. Не часть литерала, ни сложное выражение, ни идентификатор. Но только строка или число. Итак, очень распространенная ловушка - это такой запрос:
$sql = "SELECT * FROM t WHERE column LIKE '%?%'";
Если вы немного поразмышляете над этим запросом, вы поймете, что, находясь внутри одинарных кавычек, знак вопроса становится буквальным знаком вопроса без какого-либо особого значения для подготовленных утверждений.
Таким образом, нужно отправить полный строковый литерал, используя подготовленный оператор. Есть 2 возможных способа:
либо подготовьте сначала ПОЛНОЕ выражение:
$name = "%$name%"; $stm = $pdo->prepare("SELECT * FROM table WHERE name LIKE ?"); $stm->execute(array($name)); $data = $stm->fetchAll();
или используйте конкатенацию внутри запроса
$sql = "SELECT * FROM t WHERE column LIKE concat('%',?,'%')";
хотя последний кажется слишком раздутым.