Это список часто задаваемых вопросов относительно объектов данных PHP
Поскольку PDO имеет некоторые функции, неизвестные обычным пользователям PHP, вопросы относительно подготовленных операторов и обработки ошибок в PDO довольно часты. Итак, это просто место, где все их можно найти.
Если ваш вопрос был закрыт с этим списком, пожалуйста, найдите свой вопрос ниже и примените исправление к вашему коду. Также неплохо кратко рассмотреть другие вопросы, чтобы подготовиться к другим распространенным ловушкам.
Смотрите также
Чтобы иметь возможность видеть ошибки базы данных, нужно установить PDO errmode для исключений. Исключения лучше обычных ошибок по-разному: они всегда содержат трассировку стека, их можно поймать с помощью 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 для эхо сообщения об ошибке. Необязательное исключение уже отлично подходит для этой цели, так как оно будет действовать точно так же, как и другие ошибки PHP, поэтому вы можете определить поведение, используя параметры сайта, поэтому вы получите сообщение об ошибке без этого бесполезного кода. В то время как безоговорочное эхо-сообщение об ошибке может выявить некоторую конфиденциальную информацию потенциальному злоумышленнику, но запутать честного посетителя.
- Пользовательский обработчик исключений может быть добавлен позже, но не требуется. Специально для новых пользователей рекомендуется использовать необработанные исключения, поскольку они чрезвычайно информативны, полезны и безопасны.
- Используйте
try..catch
только в том случае, если вы собираетесь справиться с самой ошибкой – скажем, откат транзакции.
Для целей совместимости 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();
-$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();
Подготовленный оператор может представлять только полный литерал данных . Не является частью литерального, не сложного выражения или идентификатора. Но только строка или номер . Итак, очень распространенная ошибка – это такой запрос:
$sql = "SELECT * FROM t WHERE column LIKE '%?%'";
Если вы немного поразмыслите над этим запросом, вы поймете, что, находясь внутри одинарных кавычек, знак вопроса становится буквальным вопросительным знаком, без какого-либо особого значения для подготовленных операторов.
Итак, нужно отправить полный строковый литерал с помощью подготовленного оператора. Существует два возможных способа:
либо сначала подготовьте FULL выражение:
$name = "%$name%"; $stm = $pdo->prepare("SELECT * FROM table WHERE name LIKE ?"); $stm->execute(array($name)); $data = $stm->fetchAll();
-$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('%',?,'%')";
хотя последнее кажется слишком раздутым.