Ошибки и их обработка
PDO предлагает на выбор 3 стратегии обработки ошибок в зависимости от вашего
стиля разработки приложений.
-
PDO::ERRMODE_SILENT
До PHP 8.0.0, это был режим по умолчанию. PDO просто предоставит вам код ошибки, который
можно получить методами PDO::errorCode() и
PDO::errorInfo(). Эти методы реализованы как в объектах
запросов, так и в объектах баз данных. Если ошибка вызвана во время выполнения
кода объекта запроса, нужно вызвать метод
PDOStatement::errorCode() или
PDOStatement::errorInfo() этого объекта. Если ошибка
вызова объекта базы данных, нужно вызвать аналогичные методы у этого объекта. -
PDO::ERRMODE_WARNING
Помимо установки кода ошибки PDO выдаст обычное E_WARNING сообщение. Это может
быть полезно при отладке или тестировании, когда нужно видеть, что произошло,
но не нужно прерывать работу приложения. -
PDO::ERRMODE_EXCEPTION
Начиная с PHP 8.0.0 является режимом по умолчанию. Помимо задания кода ошибки PDO будет выбрасывать исключение
PDOException, свойства которого будут отражать
код ошибки и её описание. Этот режим также полезен при отладке, так как
сразу известно, где в программе произошла ошибка. Это позволяет быстро
локализовать и решить проблему. (Не забывайте, что если исключение
является причиной завершения работы скрипта, все активные транзакции
будут откачены.)Режим исключений также полезен, так как даёт возможность структурировать
обработку ошибок более тщательно, нежели с обычными предупреждениями PHP, а
также с меньшей вложенностью кода, чем в случае работы в тихом режиме с
явной проверкой возвращаемых значений при каждом обращении к базе данных.Подробнее об исключениях в PHP смотрите в разделе Исключения.
PDO стандартизирован для работы со строковыми кодами ошибок SQL-92 SQLSTATE.
Отдельные драйверы PDO могут задавать соответствия своих собственных кодов
кодам SQLSTATE. Метод PDO::errorCode() возвращает одиночный
код SQLSTATE. Если необходима специфичная информация об ошибке, PDO предлагает
метод PDO::errorInfo(), который возвращает массив, содержащий
код SQLSTATE, код ошибки драйвера, а также строку ошибки драйвера.
Пример #1 Создание PDO объекта и установка режима обработки ошибок
<?php
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);// PDO выбросит исключение PDOException (если таблица не существует)
$dbh->query("SELECT wrongcolumn FROM wrongtable");
?>
Результат выполнения данного примера:
Fatal error: Uncaught PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'testdb.wrongtable' doesn't exist in /tmp/pdo_test.php:10 Stack trace: #0 /tmp/pdo_test.php(10): PDO->query('SELECT wrongcol...') #1 {main} thrown in /tmp/pdo_test.php on line 10
Замечание:
Метод PDO::__construct() будет всегда бросать исключение PDOException,
если соединение оборвалось, независимо от установленного значенияPDO::ATTR_ERRMODE
.
Пример #2 Создание экземпляра класса PDO и установка режима обработки ошибок в конструкторе
<?php
$dsn = 'mysql:dbname=test;host=127.0.0.1';
$user = 'googleguy';
$password = 'googleguy';$dbh = new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));// Следующий запрос приводит к ошибке уровня E_WARNING вместо исключения (когда таблица не существует)
$dbh->query("SELECT wrongcolumn FROM wrongtable");
?>
Результат выполнения данного примера:
Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.wrongtable' doesn't exist in /tmp/pdo_test.php on line 9
There are no user contributed notes for this page.
$st = $db->prepare("SELECT * FROM c6ode");
How can I check the intentional mysql error for the query in above case?
asked Jan 8, 2012 at 8:41
0
You need to set the error mode attribute PDO::ATTR_ERRMODE
to PDO::ERRMODE_EXCEPTION
.
And since you expect the exception to be thrown by the prepare()
method, you should disable the PDO::ATTR_EMULATE_PREPARES
feature. Otherwise the MySQL server doesn’t «see» the statement until it’s executed.
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->prepare('INSERT INTO DoesNotExist (x) VALUES (?)');
prints (or logs, depends on the PHP settings)
SQLSTATE[42S02]: Base table or view not found:
1146 Table 'test.doesnotexist' doesn't exist
answered Jan 8, 2012 at 8:52
VolkerKVolkerK
95.2k20 gold badges163 silver badges226 bronze badges
1
I’m using this without any additional settings:
if (!$st->execute()) {
print_r($st->errorInfo());
}
The Codesee
3,6945 gold badges38 silver badges74 bronze badges
answered Jan 8, 2012 at 8:48
ladarladar
5,8563 gold badges26 silver badges38 bronze badges
0
I’m guessing that your complaint is that the exception is not firing. PDO is most likely configured to not throw exceptions. Enable them with this:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
answered Jan 8, 2012 at 8:45
Steve RukutsSteve Rukuts
9,1373 gold badges49 silver badges72 bronze badges
2
a quick way to see your errors whilst testing:
$error= $st->errorInfo();
echo $error[2];
answered Jan 15, 2014 at 11:19
LanLan
1,8742 gold badges20 silver badges37 bronze badges
0
/* Provoke an error — the BONES table does not exist */
$sth = $dbh->prepare('SELECT skull FROM bones');
$sth->execute();
echo "nPDOStatement::errorInfo():n";
$arr = $sth->errorInfo();
print_r($arr);
output
Array
(
[0] => 42S02
[1] => -204
[2] => [IBM][CLI Driver][DB2/LINUX] SQL0204N "DANIELS.BONES" is an undefined name. SQLSTATE=42704
)
answered Jul 5, 2017 at 9:07
1
Вернуться к: PDO
PDO предлагает на выбор 3 стратегии обработки ошибок в зависимости от вашего
стиля разработки приложений.
-
PDO::ERRMODE_SILENT
Это режим по умолчанию. PDO просто предоставит вам код ошибки, который
можно получить методами PDO::errorCode() и
PDO::errorInfo(). Эти методы реализованы как в объектах
запросов так и в объектах баз данных. Если ошибка вызвана во время выполнения
кода объекта запроса, нужно вызвать метод
PDOStatement::errorCode() или
PDOStatement::errorInfo() этого объекта. Если ошибка
вызова объекта базы данных, нужно вызвать аналогичные методы у этого объекта. -
PDO::ERRMODE_WARNING
Помимо задания кода ошибки PDO выдаст обычное E_WARNING сообщение. Это может
быть полезно при отладке или тестировании, когда нужно видеть, что произошло,
но не нужно прерывать работу приложения. -
PDO::ERRMODE_EXCEPTION
Помимо задания кода ошибки PDO будет выбрасывать исключение
PDOException, свойства которого будут отражать
код ошибки и ее описание. Этот режим также полезен при отладке, так как
сразу известно, где в программе произошла ошибка. Это позволяет быстро
локализовать и решить проблему. (Не забывайте, что если исключение
является причиной завершения работы скрипта, все активные транзакции
будут откачены.)Режим исключений также полезен, так как дает возможность структурировать
обработку ошибок более тщательно, нежели с обычными PHP предупреждениями, а
также с меньшей вложенностью кода, чем в случае работы в тихом режиме с
явной проверкой возвращаемых значений при каждом обращении к базе данных.Подробнее об исключениях в PHP см. в разделе Исключения.
PDO стандартизирован для работы со строковыми кодами ошибок SQL-92 SQLSTATE.
Отдельные PDO драйверы могут задавать соответствия своих собственных кодов
кодам SQLSTATE. Метод PDO::errorCode() возвращает одиночный
SQLSTATE код. Если необходима специфичная информация об ошибке, PDO предлагает
метод PDO::errorInfo(), который возвращает массив, содержащий
SQLSTATE код, код ошибки драйвера, а также строку ошибки драйвера.
Пример #1 Создание PDO объекта и задание режима обработки ошибок
<?php
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
try {
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Подключение не удалось: ' . $e->getMessage();
}?>
Замечание:
Метод PDO::__construct() будет всегда бросать исключение PDOException,
если соединение оборвалось, независимо от установленного значенияPDO::ATTR_ERRMODE
.
Непойманные исключения фатальны.
Пример #2 Создание экземпляра класса PDO и задание режима обработки ошибок в конструкторе
<?php
$dsn = 'mysql:dbname=test;host=127.0.0.1';
$user = 'googleguy';
$password = 'googleguy';/*
По прежнему оберните конструктор в блок try/catch, так как, даже при установке ERRMODE в WARNING,
PDO::__construct всегда будет бросать исключение PDOException, если соединение оборвалось.
*/
try {
$dbh = new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
} catch (PDOException $e) {
echo 'Соединение оборвалось: ' . $e->getMessage();
exit;
}// Следующий запрос приводит к ошибке уровня E_WARNING вместо исключения (когда таблица не существует)
$dbh->query("SELECT wrongcolumn FROM wrongtable");
?>
Результат выполнения данного примера:
Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.wrongtable' doesn't exist in /tmp/pdo_test.php on line 18
Вернуться к: PDO
В этой статье разговор пойдет о PHP Data Objects (PDO) — расширение для PHP, предоставляющее разработчику универсальный интерфейс для доступа к различным базам данных.
В чем преимущество PDO? Этот вопрос можно раскрыть тремя пунктами:
- Универсальный интерфейс для работы с различными базами данных. Разработчик может легко перевести свое веб-приложение на другую СУБД, поменяв при этом всего пару строк кода.
- Высокая скорость работы.
- Подготовленные выражения, о которых мы поговорим чуть позже.
На данный момент расширение PDO может поддерживать СУБД для которой существует PDO-драйвер:
- PDO_CUBRID (CUBRID)
- PDO_DBLIB (FreeTDS, Microsoft SQL Server, Sybase)
- PDO_FIREBIRD (Firebird, Interbase 6)
- PDO_IBM (IBM DB2)
- PDO_INFORMIX (IBM Informix Dynamic Server)
- PDO_MYSQL (MySQL 3.x/4.x/5.x)
- PDO_OCI (Oracle Call Interface)
- PDO_ODBC (ODBC v3 (IBM DB2, unixODBC and win32 ODBC))
- PDO_PGSQL (PostgreSQL)
- PDO_SQLITE (SQLite 3 and SQLite 2)
- PDO_SQLSRV (Microsoft SQL Serve )
- PDO_4D (4D)
Подключение к базе данных
В зависимости от выбранной СУБД, способ подключения может незначительно отличаться. Подключение к популярным СУБД:
// MуSQL $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); // PostgreSQL $DBH = new PDO("pgsql:host=$host;dbname=$dbname", $user, $pass); //MS SQL $DBH = new PDO("mssql:host=$host;dbname=$dbname", $user, $pass); // SQLite $DBH = new PDO("sqlite:my/database/path/database.db");
Обработка ошибок и исключения
Обязательно заключайте подключение к базе данных в блок try/catch:
try { $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); } catch(PDOException $e) { echo "Нет соединения с базой данных"; }
Иначе, в случае ошибки, в браузер будет выкинут Fatal error, в котором будут раскрыты все подробности вашего соединения, с логином и паролем.
PDO умеет выбрасывать исключения при ошибках, поэтому все операции с базой, по хорошему, должны находиться в блоке try/catch.
PDO имеет три режима обработки исключения:
- PDO::ERRMODE_SILENT — режим по умолчанию, ошибки генерируются по такому же принципу, как в расширениях mysql или mysqli. После возникновения ошибки скрипт продолжит работу.
- PDO::ERRMODE_WARNING — режим вызовет стандартное сообщение E_WARNING и позволит скрипту продолжить работу.
- PDO::ERRMODE_EXCEPTION — режим выбрасывает исключение, что позволяет обрабатывать ошибки и скрывать важную информацию от посторонних глаз.
Чтобы установить необходимый уровень контроля ошибок необходимо вызвать метод $this->setAttribute после подключения к базе данных.
try { $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e) { echo "Нет соединения с базой данных"; }
Подготовленные выражения или Prepared Statements
Подготовленные выражения — это заранее скомпилированное SQL-выражение, которое может быть многократно выполнено путем отправки серверу лишь различных наборов данных. Дополнительным преимуществом является невозможность провести SQL-инъекцию.
За подготовленные выражения отвечает метод $DBH->prepare. Им и рекомендуется всегда пользоваться.
Сразу хочу отметить, что выполнить запрос в PDO можно тремя методами:
- $DBH->exec — используется для запросов, которые не возвращают никаких данных. Метод возвращает количество затронутых им записей, или FALSE в случае ошибки.
$count_row = $DBH->exec("DELETE FROM users");
- $DBH->query – используется выполнения не защищенных запросов, и возвращает результат или FALSE в случаи ошибки. Например, им можно выполнять простые запросы.
$DBH->query("SET NAMES 'cp1251'"); $DBH->query("SELECT * FROM users"); $DBH->query("DELETE FROM users");
- $DBH->prepare + $STH->execute — используется для подготовки выражений и выполнения запроса.
// безымянные placeholders $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (?, ?, ?)");
// именные placeholders $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (:name, :phone, :city)");
После подготовки, запрос выполняется методом $STH->execute($data).
// безымянные placeholders $data = array(); $data[] = 'Alersander'; $data[] = '+7 000 123 45 67'; $data[] = 'St. Petersburg'; $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (?, ?, ?)"); $STH->execute($data);
// именные placeholders $data = array(); $data['name'] = 'Alersander'; $data['phone'] = '+7 000 123 45 67'; $data['city'] = 'St. Petersburg'; $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (:name, :phone, :city)"); $STH->execute($data);
Выборка данных
Для выборки с произвольными параметрами тоже будем использовать метод $DBH->prepare. Данные выборки можно получить с помощью методов:
- $STH->fetch — выбирает следующую строку и возвращает в необходимом виде.
- $STH->fetchAll — возвращает массив всех выбранных строк.
- $STH->fetchObject — выбирает следующую строку и возвращает ее как объект.
Я буду рассматривать только первый метод, т.к. он универсальный и предоставляет разработчику, всё, что ему необходимо.
Методу $STH->fetch можно указать, в каком виде нам нужно предоставить результат:
- PDO::FETCH_BOTH (по умолчанию) — возвращает числовой и ассоциативный массив;
- PDO::FETCH_ASSOC — возвращает массив ассоциативный с названиями столбцов;
- PDO::FETCH_NUM — возвращает массив числовыми ключами в виде порядковых номеров столбцов;
- PDO::FETCH_OBJ — возвращает анонимный объект со свойствами, соответствующими именам столбцов;
- PDO::FETCH_BOUND — присваивает значения столбцов соответствующим переменным, заданным с помощью метода $STH->bindColumn();
- PDO::FETCH_CLASS — присваивает значения столбцов соответствующим свойствам указанного класса. Если для какого-то столбца свойства нет, оно будет создано;
- PDO::FETCH_INTO — обновляет существующий экземпляр указанного класса;
- PDO::FETCH_LAZY — объединяет в себе PDO::FETCH_BOTH и PDO::FETCH_OBJ.
$STH = $DBH->prepare("SELECT name, phone, city FROM users"); $STH->execute(); while($res = $STH->fetch(PDO::FETCH_ASSOC)) { echo $res['name']; } $STH = $DBH->prepare("SELECT name, phone, city FROM users"); $STH->execute(); while($res = $STH->fetch(PDO::FETCH_OBJ)) { echo $res->name; }
Закрытие соединения и освобождение буфера запроса
В PDO нет специальных методов для этих целей. Закрыть соединение с базой данных можно путем переопределения переменных:
$DBH = null; $STH = null;
Полезные методы
- $DBH->lastInsertId() — возвращает id последней вставленной записи.
- $DBH->query(string) — экранирует специальные символы в строковых данных таким образом, что их становится безопасно использовать в запросах.
- $STH->rowCount() — возвращает количество затронутых записей последним запросом.
Обработка ошибок PDO
Лично мне не нравится, что если я не заключаю все запросы в блок try/catch, то PDO выкидывает Fatal error со всеми интимными подробностями моего запроса. В промышленном приложении заключать каждый запрос в блок try/catch, это идиотизм!
Поэтому мы поступим следующим образом — немного расширим классы PDO и PDOStatement:
class DB extends PDO { public $error = false; // выводить сообщения об ошибках на экран? (true/false) public function __construct($dsn, $username='', $password='', $driver_options=array()) { try { parent::__construct($dsn, $username, $password, $driver_options); $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DBStatement', array($this))); $this->query("SET NAMES 'cp1251'"); } catch(PDOException $e) { echo "Произошла ошибка в работе с базой данных..."; exit(); } } public function prepare($sql, $driver_options=array()) { try { return parent::prepare($sql, $driver_options); } catch(PDOException $e) { $this->error($e->getMessage()); } } public function query($sql) { try { return parent::query($sql); } catch(PDOException $e) { $this->error($e->getMessage()); } } public function exec($sql) { try { return parent::exec($sql); } catch(PDOException $e) { $this->error($e->getMessage()); } } public function error($msg) { if($this->error) { echo $msg; } else { echo "Произошла ошибка в работе с базой данных..."; } exit(); } }
class DBStatement extends PDOStatement { protected $DBH; protected function __construct($DBH) { $this->DBH = $DBH; } public function execute($data=array()) { try { return parent::execute($data); } catch(PDOException $e) { $this->DBH->error($e->getMessage()); } } }
Как видите, я реализую свои два класса DB и DBStatement, наследуя классы PDO и PDOStatement. Классы реализуют все необходимые мне для работы над ошибками методы, которые обрабатываются блоком try/catch.
$DBH = new DB("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->error = true; // Для отладки выводим сообщения об ошибках на экран. $STH = $DBH->prepare("SELEC * FROM users"); $STH->execute($data);
Как видите, я совершил опечатку в операторе и могу получить всю необходимую информацию об этой ошибке.
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELEC * FROM users' at line 1
Расширение функционала
Также бывает полезно расширить функционал PDO. Например, часто требуется получить количество записей в таблице.
Стандартными методами это можно делать следующим образом:
$data = array(); $data['user_id'] = 1; $STH = $DBH->prepare("SELECT COUNT(*) as count FROM users WHERE user_id=:user_id"); $STH->execute($data); echo $STH->fetch(PDO::FETCH_OBJ)->count;
Не слишком удобно. Поэтому реализуем в нашем классе методом count:
class DB extends PDO { // .................. public function count($sql, $data) { $res = $this->prepare($sql); $res->execute($data); return $res->fetch(PDO::FETCH_OBJ); } // .................. }
Получаем количество записей:
$DBH = new DB("mysql:host=$host;dbname=$dbname", $user, $pass); echo $DBH->count("SELECT COUNT(*) as count FROM users WHERE user_id=:user_id", array('user_id'=>'1'))->count;
Свои методы это конечно хорошо, но мне бы ещё хотелось писать все одной строкой. К сожалению, стандартными возможностями я не могу этого сделать:
$res = $DBH->prepare("SELECT * FROM users WHERE id_user=:id_user") ->execute(array('id_user'=>'1')) ->fetch(PDO::FETCH_ASSOC); echo $res['name']; // или так echo $DBH->prepare("SELECT *FROM users WHERE id_user=:id_user") ->execute(array('id_user'=>'1')) ->fetch(PDO::FETCH_OB) ->name;
Метод execute возвращает бесполезное логическое значение об успехе операции, а не объект DBStatement.
Допиливаем свой метод execute:
public function execute($data=array()) { try { parent::execute($data); return $this; } catch(PDOException $e) { $this->DBH->error($e->getMessage()); } }
Проверяем результат:
echo $DBH->prepare("SELECT COUNT(*) as count FROM users WHERE city=:city") ->execute(array('city'=>'St. Petersburg')) ->fetch(PDO::FETCH_OBJ) ->count;
Источник
Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)
PDO::errorInfo —
Получает расширенную информацию об ошибке, произошедшей в ходе
последнего обращения к базе данных
Описание
public PDO::errorInfo(): array
Список параметров
У этой функции нет параметров.
Возвращаемые значения
PDO::errorInfo() возвращает массив с информацией об ошибке,
произошедшей в ходе выполнения последней операции с базой данных. Массив
содержит как минимум следующие поля:
Элемент | Информация |
---|---|
0 | Код ошибки SQLSTATE (пятисимвольный идентификатор, определённый в стандарте ANSI SQL). |
1 | Код ошибки, заданный драйвером. |
2 | Сообщение об ошибке, заданное драйвером |
Замечание:
Если не задан SQLSTATE код или драйвер не сообщил об ошибке, то элементы
следующие за нулевым будут иметь значениеnull
.
PDO::errorInfo() выдаёт информацию об ошибке только для операций,
совершаемых с базой данных напрямую из PDO. Если создать объект PDOStatement
методами PDO::prepare() или
PDO::query(), и вызвать ошибку его методами,
PDO::errorInfo() эту ошибку не отобразит. Вам нужно вызвать
PDOStatement::errorInfo(), чтобы получить информации об ошибках для операции,
выполняемой на определённом объекте PDOStatement.
Примеры
Пример #1
Вывод полей массива errorInfo() для PDO_ODBC подключения к базе данных DB2
<?php
/* Спровоцируем синтаксическую ошибку SQL */
$stmt = $dbh->prepare('bogus sql');
if (!$stmt) {
echo "nPDO::errorInfo():n";
print_r($dbh->errorInfo());
}
?>
Результат выполнения данного примера:
PDO::errorInfo(): Array ( [0] => HY000 [1] => 1 [2] => near "bogus": syntax error )
Смотрите также
- PDO::errorCode() — Возвращает код SQLSTATE результата последней операции с базой данных
- PDOStatement::errorCode() — Получает код SQLSTATE, связанный с последней операцией в объекте PDOStatement
- PDOStatement::errorInfo() — Получение расширенной информации об ошибке, произошедшей в результате работы
объекта PDOStatement
alagar86 at gmail dot com ¶
12 years ago
Please note : that this example won't work if PDO::ATTR_EMULATE_PREPARES is true.
You should set it to false
<?php
$dbh
->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);$stmt = $dbh->prepare('bogus sql');
if (!
$stmt) {
echo
"nPDO::errorInfo():n";print_r($dbh->errorInfo());
}
?>
quickshiftin at gmail dot com ¶
15 years ago
here are the error codes for sqlite, straight from their site:
The error codes for SQLite version 3 are unchanged from version 2. They are as follows:
#define SQLITE_OK 0 /* Successful result */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
mazen at mindcraftinc dot com ¶
14 years ago
Some PDO drivers return a larger array. For example, the SQL Server driver returns 5 values.
For example:
<?php
$numRows
= $db->exec("DELETE FROM [TableName] WHERE ID between 6 and 17");print_r($db->errorInfo());?>
Result:
Array
(
[0] => 00000
[1] => 0
[2] => (null) [0] (severity 0) []
[3] => 0
[4] => 0
)
Ошибки и их обработка
PDO предлагает на выбор 3 стратегии обработки ошибок в зависимости от вашего
стиля разработки приложений.
-
PDO::ERRMODE_SILENT
До PHP 8.0.0, это был режим по умолчанию. PDO просто предоставит вам код ошибки, который
можно получить методами PDO::errorCode() и
PDO::errorInfo(). Эти методы реализованы как в объектах
запросов, так и в объектах баз данных. Если ошибка вызвана во время выполнения
кода объекта запроса, нужно вызвать метод
PDOStatement::errorCode() или
PDOStatement::errorInfo() этого объекта. Если ошибка
вызова объекта базы данных, нужно вызвать аналогичные методы у этого объекта. -
PDO::ERRMODE_WARNING
Помимо установки кода ошибки PDO выдаст обычное E_WARNING сообщение. Это может
быть полезно при отладке или тестировании, когда нужно видеть, что произошло,
но не нужно прерывать работу приложения. -
PDO::ERRMODE_EXCEPTION
Начиная с PHP 8.0.0 является режимом по умолчанию. Помимо задания кода ошибки PDO будет выбрасывать исключение
PDOException, свойства которого будут отражать
код ошибки и её описание. Этот режим также полезен при отладке, так как
сразу известно, где в программе произошла ошибка. Это позволяет быстро
локализовать и решить проблему. (Не забывайте, что если исключение
является причиной завершения работы скрипта, все активные транзакции
будут откачены.)Режим исключений также полезен, так как даёт возможность структурировать
обработку ошибок более тщательно, нежели с обычными предупреждениями PHP, а
также с меньшей вложенностью кода, чем в случае работы в тихом режиме с
явной проверкой возвращаемых значений при каждом обращении к базе данных.Подробнее об исключениях в PHP смотрите в разделе Исключения.
PDO стандартизирован для работы со строковыми кодами ошибок SQL-92 SQLSTATE.
Отдельные драйверы PDO могут задавать соответствия своих собственных кодов
кодам SQLSTATE. Метод PDO::errorCode() возвращает одиночный
код SQLSTATE. Если необходима специфичная информация об ошибке, PDO предлагает
метод PDO::errorInfo(), который возвращает массив, содержащий
код SQLSTATE, код ошибки драйвера, а также строку ошибки драйвера.
Пример #1 Создание PDO объекта и установка режима обработки ошибок
<?php
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);// PDO выбросит исключение PDOException (если таблица не существует)
$dbh->query("SELECT wrongcolumn FROM wrongtable");
?>
Результат выполнения данного примера:
Fatal error: Uncaught PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'testdb.wrongtable' doesn't exist in /tmp/pdo_test.php:10 Stack trace: #0 /tmp/pdo_test.php(10): PDO->query('SELECT wrongcol...') #1 {main} thrown in /tmp/pdo_test.php on line 10
Замечание:
Метод PDO::__construct() будет всегда бросать исключение PDOException,
если соединение оборвалось, независимо от установленного значенияPDO::ATTR_ERRMODE
.
Пример #2 Создание экземпляра класса PDO и установка режима обработки ошибок в конструкторе
<?php
$dsn = 'mysql:dbname=test;host=127.0.0.1';
$user = 'googleguy';
$password = 'googleguy';$dbh = new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));// Следующий запрос приводит к ошибке уровня E_WARNING вместо исключения (когда таблица не существует)
$dbh->query("SELECT wrongcolumn FROM wrongtable");
?>
Результат выполнения данного примера:
Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.wrongtable' doesn't exist in /tmp/pdo_test.php on line 9
There are no user contributed notes for this page.
You need to set the error mode attribute PDO::ATTR_ERRMODE to PDO::ERRMODE_EXCEPTION.
And since you expect the exception to be thrown by the prepare() method you should disable the PDO::ATTR_EMULATE_PREPARES* feature. Otherwise the MySQL server doesn’t «see» the statement until it’s executed.
<?php
try {
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->prepare('INSERT INTO DoesNotExist (x) VALUES (?)');
}
catch(Exception $e) {
echo 'Exception -> ';
var_dump($e->getMessage());
}
prints (in my case)
Exception -> string(91) "SQLSTATE[42S02]: Base table or view not found:
1146 Table 'test.doesnotexist' doesn't exist"
see http://wezfurlong.org/blog/2006/apr/using-pdo-mysql/
EMULATE_PREPARES=true seems to be the default setting for the pdo_mysql driver right now.
The query cache thing has been fixed/change since then and with the mysqlnd driver I hadn’t problems with EMULATE_PREPARES=false (though I’m only a php hobbyist, don’t take my word on it…)
*) and then there’s PDO::MYSQL_ATTR_DIRECT_QUERY — I must admit that I don’t understand the interaction of those two attributes (yet?), so I set them both, like
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
PDO::ATTR_EMULATE_PREPARES=>false,
PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));
Вернуться к: PDO
PDO предлагает на выбор 3 стратегии обработки ошибок в зависимости от вашего
стиля разработки приложений.
-
PDO::ERRMODE_SILENT
Это режим по умолчанию. PDO просто предоставит вам код ошибки, который
можно получить методами PDO::errorCode() и
PDO::errorInfo(). Эти методы реализованы как в объектах
запросов так и в объектах баз данных. Если ошибка вызвана во время выполнения
кода объекта запроса, нужно вызвать метод
PDOStatement::errorCode() или
PDOStatement::errorInfo() этого объекта. Если ошибка
вызова объекта базы данных, нужно вызвать аналогичные методы у этого объекта. -
PDO::ERRMODE_WARNING
Помимо задания кода ошибки PDO выдаст обычное E_WARNING сообщение. Это может
быть полезно при отладке или тестировании, когда нужно видеть, что произошло,
но не нужно прерывать работу приложения. -
PDO::ERRMODE_EXCEPTION
Помимо задания кода ошибки PDO будет выбрасывать исключение
PDOException, свойства которого будут отражать
код ошибки и ее описание. Этот режим также полезен при отладке, так как
сразу известно, где в программе произошла ошибка. Это позволяет быстро
локализовать и решить проблему. (Не забывайте, что если исключение
является причиной завершения работы скрипта, все активные транзакции
будут откачены.)Режим исключений также полезен, так как дает возможность структурировать
обработку ошибок более тщательно, нежели с обычными PHP предупреждениями, а
также с меньшей вложенностью кода, чем в случае работы в тихом режиме с
явной проверкой возвращаемых значений при каждом обращении к базе данных.Подробнее об исключениях в PHP см. в разделе Исключения.
PDO стандартизирован для работы со строковыми кодами ошибок SQL-92 SQLSTATE.
Отдельные PDO драйверы могут задавать соответствия своих собственных кодов
кодам SQLSTATE. Метод PDO::errorCode() возвращает одиночный
SQLSTATE код. Если необходима специфичная информация об ошибке, PDO предлагает
метод PDO::errorInfo(), который возвращает массив, содержащий
SQLSTATE код, код ошибки драйвера, а также строку ошибки драйвера.
Пример #1 Создание PDO объекта и задание режима обработки ошибок
<?php
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
try {
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Подключение не удалось: ' . $e->getMessage();
}?>
Замечание:
Метод PDO::__construct() будет всегда бросать исключение PDOException,
если соединение оборвалось, независимо от установленного значенияPDO::ATTR_ERRMODE
.
Непойманные исключения фатальны.
Пример #2 Создание экземпляра класса PDO и задание режима обработки ошибок в конструкторе
<?php
$dsn = 'mysql:dbname=test;host=127.0.0.1';
$user = 'googleguy';
$password = 'googleguy';/*
По прежнему оберните конструктор в блок try/catch, так как, даже при установке ERRMODE в WARNING,
PDO::__construct всегда будет бросать исключение PDOException, если соединение оборвалось.
*/
try {
$dbh = new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
} catch (PDOException $e) {
echo 'Соединение оборвалось: ' . $e->getMessage();
exit;
}// Следующий запрос приводит к ошибке уровня E_WARNING вместо исключения (когда таблица не существует)
$dbh->query("SELECT wrongcolumn FROM wrongtable");
?>
Результат выполнения данного примера:
Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.wrongtable' doesn't exist in /tmp/pdo_test.php on line 18
Вернуться к: PDO
Содержание
- PDO::errorInfo
- Description
- Parameters
- Return Values
- Examples
- See Also
- User Contributed Notes 3 notes
- Ошибки и их обработка
- Ошибки и их обработка
- PDO::errorCode
- Description
- Parameters
- Return Values
- Examples
- See Also
- CMCDragonkai / PDO Error Handling.md
PDO::errorInfo
(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)
PDO::errorInfo — Fetch extended error information associated with the last operation on the database handle
Description
Parameters
This function has no parameters.
Return Values
PDO::errorInfo() returns an array of error information about the last operation performed by this database handle. The array consists of at least the following fields:
Element | Information |
---|---|
SQLSTATE error code (a five characters alphanumeric identifier defined in the ANSI SQL standard). | |
1 | Driver-specific error code. |
2 | Driver-specific error message. |
If the SQLSTATE error code is not set or there is no driver-specific error, the elements following element 0 will be set to null .
PDO::errorInfo() only retrieves error information for operations performed directly on the database handle. If you create a PDOStatement object through PDO::prepare() or PDO::query() and invoke an error on the statement handle, PDO::errorInfo() will not reflect the error from the statement handle. You must call PDOStatement::errorInfo() to return the error information for an operation performed on a particular statement handle.
Examples
Example #1 Displaying errorInfo() fields for a PDO_ODBC connection to a DB2 database
The above example will output:
See Also
- PDO::errorCode() — Fetch the SQLSTATE associated with the last operation on the database handle
- PDOStatement::errorCode() — Fetch the SQLSTATE associated with the last operation on the statement handle
- PDOStatement::errorInfo() — Fetch extended error information associated with the last operation on the statement handle
User Contributed Notes 3 notes
Please note : that this example won’t work if PDO::ATTR_EMULATE_PREPARES is true.
You should set it to false
-> setAttribute ( PDO :: ATTR_EMULATE_PREPARES , false );
$stmt = $dbh -> prepare ( ‘bogus sql’ );
if (! $stmt ) <
echo «nPDO::errorInfo():n» ;
print_r ( $dbh -> errorInfo ());
>
?>
here are the error codes for sqlite, straight from their site:
The error codes for SQLite version 3 are unchanged from version 2. They are as follows:
#define SQLITE_OK 0 /* Successful result */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
Some PDO drivers return a larger array. For example, the SQL Server driver returns 5 values.
For example:
= $db -> exec ( «DELETE FROM [TableName] WHERE ID between 6 and 17» );
print_r ( $db -> errorInfo ());
?>
Result:
Array
(
[0] => 00000
[1] => 0
[2] => (null) [0] (severity 0) []
[3] => 0
[4] => 0
)
Источник
Ошибки и их обработка
PDO предлагает на выбор 3 стратегии обработки ошибок в зависимости от вашего стиля разработки приложений.
PDO::ERRMODE_SILENT
До PHP 8.0.0, это был режим по умолчанию. PDO просто предоставит вам код ошибки, который можно получить методами PDO::errorCode() и PDO::errorInfo() . Эти методы реализованы как в объектах запросов, так и в объектах баз данных. Если ошибка вызвана во время выполнения кода объекта запроса, нужно вызвать метод PDOStatement::errorCode() или PDOStatement::errorInfo() этого объекта. Если ошибка вызова объекта базы данных, нужно вызвать аналогичные методы у этого объекта.
PDO::ERRMODE_WARNING
Помимо установки кода ошибки PDO выдаст обычное E_WARNING сообщение. Это может быть полезно при отладке или тестировании, когда нужно видеть, что произошло, но не нужно прерывать работу приложения.
PDO::ERRMODE_EXCEPTION
Начиная с PHP 8.0.0 является режимом по умолчанию. Помимо задания кода ошибки PDO будет выбрасывать исключение PDOException , свойства которого будут отражать код ошибки и её описание. Этот режим также полезен при отладке, так как сразу известно, где в программе произошла ошибка. Это позволяет быстро локализовать и решить проблему. (Не забывайте, что если исключение является причиной завершения работы скрипта, все активные транзакции будут откачены.)
Режим исключений также полезен, так как даёт возможность структурировать обработку ошибок более тщательно, нежели с обычными предупреждениями PHP, а также с меньшей вложенностью кода, чем в случае работы в тихом режиме с явной проверкой возвращаемых значений при каждом обращении к базе данных.
Подробнее об исключениях в PHP смотрите в разделе Исключения.
PDO стандартизирован для работы со строковыми кодами ошибок SQL-92 SQLSTATE. Отдельные драйверы PDO могут задавать соответствия своих собственных кодов кодам SQLSTATE. Метод PDO::errorCode() возвращает одиночный код SQLSTATE. Если необходима специфичная информация об ошибке, PDO предлагает метод PDO::errorInfo() , который возвращает массив, содержащий код SQLSTATE, код ошибки драйвера, а также строку ошибки драйвера.
Пример #1 Создание PDO объекта и установка режима обработки ошибок
= ‘mysql:dbname=testdb;host=127.0.0.1’ ;
$user = ‘dbuser’ ;
$password = ‘dbpass’ ;
$dbh = new PDO ( $dsn , $user , $password );
$dbh -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );
// PDO выбросит исключение PDOException (если таблица не существует)
$dbh -> query ( «SELECT wrongcolumn FROM wrongtable» );
?>
Результат выполнения данного примера:
Метод PDO::__construct() будет всегда бросать исключение PDOException , если соединение оборвалось, независимо от установленного значения PDO::ATTR_ERRMODE .
Пример #2 Создание экземпляра класса PDO и установка режима обработки ошибок в конструкторе
= ‘mysql:dbname=test;host=127.0.0.1’ ;
$user = ‘googleguy’ ;
$password = ‘googleguy’ ;
$dbh = new PDO ( $dsn , $user , $password , array( PDO :: ATTR_ERRMODE => PDO :: ERRMODE_WARNING ));
// Следующий запрос приводит к ошибке уровня E_WARNING вместо исключения (когда таблица не существует)
$dbh -> query ( «SELECT wrongcolumn FROM wrongtable» );
?>
Источник
Ошибки и их обработка
PDO предлагает на выбор 3 стратегии обработки ошибок в зависимости от вашего стиля разработки приложений.
PDO::ERRMODE_SILENT
Это режим по умолчанию. PDO просто предоставит вам код ошибки, который можно получить методами PDO::errorCode() и PDO::errorInfo() . Эти методы реализованы как в объектах запросов так и в объектах баз данных. Если ошибка вызвана во время выполнения кода объекта запроса, нужно вызвать метод PDOStatement::errorCode() или PDOStatement::errorInfo() этого объекта. Если ошибка вызова объекта базы данных, нужно вызвать аналогичные методы у этого объекта.
PDO::ERRMODE_WARNING
Помимо задания кода ошибки PDO выдаст обычное E_WARNING сообщение. Это может быть полезно при отладке или тестировании, когда нужно видеть, что произошло, но не нужно прерывать работу приложения.
PDO::ERRMODE_EXCEPTION
Помимо задания кода ошибки PDO будет выбрасывать исключение PDOException, свойства которого будут отражать код ошибки и ее описание. Этот режим также полезен при отладке, так как сразу известно, где в программе произошла ошибка. Это позволяет быстро локализовать и решить проблему. (Не забывайте, что если исключение является причиной завершения работы скрипта, все активные транзакции будут откачены.)
Режим исключений также полезен, так как дает возможность структурировать обработку ошибок более тщательно, нежели с обычными PHP предупреждениями, а также с меньшей вложенностью кода, чем в случае работы в тихом режиме с явной проверкой возвращаемых значений при каждом обращении к базе данных.
Подробнее об исключениях в PHP см. в разделе Исключения.
PDO стандартизирован для работы со строковыми кодами ошибок SQL-92 SQLSTATE. Отдельные PDO драйверы могут задавать соответствия своих собственных кодов кодам SQLSTATE. Метод PDO::errorCode() возвращает одиночный SQLSTATE код. Если необходима специфичная информация об ошибке, PDO предлагает метод PDO::errorInfo() , который возвращает массив, содержащий SQLSTATE код, код ошибки драйвера, а также строку ошибки драйвера.
Пример #1 Создание PDO объекта и задание режима обработки ошибок
= ‘mysql:dbname=testdb;host=127.0.0.1’ ;
$user = ‘dbuser’ ;
$password = ‘dbpass’ ;
try <
$dbh = new PDO ( $dsn , $user , $password );
$dbh -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );
> catch ( PDOException $e ) <
echo ‘Подключение не удалось: ‘ . $e -> getMessage ();
>
Метод PDO::__construct() будет всегда бросать исключение PDOException, если соединение оборвалось, независимо от установленного значения PDO::ATTR_ERRMODE . Непойманные исключения фатальны.
Пример #2 Создание экземпляра класса PDO и задание режима обработки ошибок в конструкторе
= ‘mysql:dbname=test;host=127.0.0.1’ ;
$user = ‘googleguy’ ;
$password = ‘googleguy’ ;
/*
По прежнему оберните конструктор в блок try/catch, так как, даже при установке ERRMODE в WARNING,
PDO::__construct всегда будет бросать исключение PDOException, если соединение оборвалось.
*/
try <
$dbh = new PDO ( $dsn , $user , $password , array( PDO :: ATTR_ERRMODE => PDO :: ERRMODE_WARNING ));
> catch ( PDOException $e ) <
echo ‘Соединение оборвалось: ‘ . $e -> getMessage ();
exit;
>
// Следующий запрос приводит к ошибке уровня E_WARNING вместо исключения (когда таблица не существует)
$dbh -> query ( «SELECT wrongcolumn FROM wrongtable» );
?>
Источник
PDO::errorCode
(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)
PDO::errorCode — Fetch the SQLSTATE associated with the last operation on the database handle
Description
Parameters
This function has no parameters.
Return Values
Returns an SQLSTATE, a five characters alphanumeric identifier defined in the ANSI SQL-92 standard. Briefly, an SQLSTATE consists of a two characters class value followed by a three characters subclass value. A class value of 01 indicates a warning and is accompanied by a return code of SQL_SUCCESS_WITH_INFO. Class values other than ’01’, except for the class ‘IM’, indicate an error. The class ‘IM’ is specific to warnings and errors that derive from the implementation of PDO (or perhaps ODBC, if you’re using the ODBC driver) itself. The subclass value ‘000’ in any class indicates that there is no subclass for that SQLSTATE.
PDO::errorCode() only retrieves error codes for operations performed directly on the database handle. If you create a PDOStatement object through PDO::prepare() or PDO::query() and invoke an error on the statement handle, PDO::errorCode() will not reflect that error. You must call PDOStatement::errorCode() to return the error code for an operation performed on a particular statement handle.
Returns null if no operation has been run on the database handle.
Examples
Example #1 Retrieving an SQLSTATE code
/* Provoke an error — the BONES table does not exist */
$dbh -> exec ( «INSERT INTO bones(skull) VALUES (‘lucy’)» );
echo «nPDO::errorCode(): » , $dbh -> errorCode ();
?>
The above example will output:
See Also
- PDO::errorInfo() — Fetch extended error information associated with the last operation on the database handle
- PDOStatement::errorCode() — Fetch the SQLSTATE associated with the last operation on the statement handle
- PDOStatement::errorInfo() — Fetch extended error information associated with the last operation on the statement handle
Источник
CMCDragonkai / PDO Error Handling.md
PDO Error Handling
The first step is to switch on exceptions. When bootstrapping PDO, make sure to do:
Every time you execute a PDO statement using PDOStatement::execute .
There is a possiblity of an exception being raised.
In the above we demonstrate the 3 most important methods and properties of the exception object.
The returned getCode() gives back a 5 character SQLSTATE code string. This is defined as part of the SQL standard and is meant to be generic across databases. For more information on this code: https://en.wikibooks.org/wiki/Structured_Query_Language/SQLSTATE
The returned getMessage() is a string construced by PDO which has a format of:
Where XXXXX is the SQLSTATE code, DESCRIPTION is a PHP supplied description like Syntax error or access violation or > , YYYY is the driver specific code, and finally the MESSAGE is the driver returned message.
Driver specific codes are usually more specific than the SQLSTATE code, so you can pattern match on driver specific code in order to dig down to more specific errors. For example this is the list of MySQL driver error codes and how they match to SQLSTATE codes: https://dev.mysql.com/doc/refman/en/error-messages-server.html and here’s the one for MariaDB: https://mariadb.com/kb/en/mariadb/mariadb-error-codes/
It is possible to create custom SQLSTATE codes to use for schema-specific errors that your application should handle. In MySQL, you should use the DECLARE . CONDITION syntax to give human readable names to your custom error codes. Custom error codes should avoid conflicting with existing error codes. The standard SQL specification says that classes beginning with 0, 1, 2, 3, 4, A, B, C, D, E, F and G are reserved for standard-defined classes, while other classes are vendor-specific. It also says that, when the class is standard-defined, subclasses starting with those characters (except for ‘000’) are standard-defined subclasses, while other subclasses are vendor-defined. So depending on your database, look for a range that isn’t used now and unlikely to be used in the future. Here’s an example use: 50000 for general application errors, and then start at 50001 for specific errors.
I have not found good documentation on what kind of PHP supplied descriptions are available. You can use it as kind of summary description of the error. However you have to use regex to extract it from the message string as it is not discretely provided by other means.
When you use database triggers to enforce constraints, you will probably use the 45000 SQLSTATE code, you can pattern match on 45000 to know whether it’s a trigger error or otherwise.
In order to do pattern matching easily, rather than using getMessage() or getCode() , you should instead use the errorInfo array. This provides the SQLSTATE code (still in string type), the driver specific code (in my MySQL tests, the type was integer), and the driver specific message. If you do pattern matching on the SQLSTATE code, your codebase will be somewhat more portable than pattern matching on the driver specific code.
Here is an example of pattern matching against the PDO errors. Make sure to read your database manual and know what kind of errors you’re interested in. Note that in PHP it’s possible to compare strings and integers for equality.
If the above code exists in some model, you can then rethrow and wrap the exception in a model specific exception, or handle the exception there exactly.
If you’re using an ORM that wraps the PDOException, you should always be able to get it using getPrevious() .
Handling PDO exceptions properly, can allow a clean propagation of errors from the database to the frontend of a web application, as this allows you to keep the constraints on data where the data lives and is ultimately managed. Then we avoid having to repeat validation logic from database to application.
Источник
PDO (PHP Data Objects) — расширение PHP, которое реализует взаимодействие с базами данных при помощи объектов. Профит в том, что отсутствует привязка к конкретной системе управления базами данных.
Предоставляемый интерфейс поддерживает, среди прочих, такие популярные СУБД:
- MySQL;
- SQLite;
- PostgreSQL;
- Microsoft SQL Server.
В этом руководстве представлен обзор PDO:
- Пошаговое описание работы с базами данных, начиная с установки соединения до выполнения выборки.
- Порядок использования подготовленных запросов.
- Настройка обработки ошибок.
Для работы потребуются:
- базовые знания MySQL и опыт использования команды
mysql
в консоли; - понимание основ объектно-ориентированного программирования;
- PHP >= 5.1;
- рабочая СУБД MySQL/MariaDB.
Создание тестовой базы данных и таблицы
Для начала создадим базу данных для этого руководства:
CREATE DATABASE solar_system;
GRANT ALL PRIVILEGES ON solar_system.* TO 'testuser'@'localhost'
IDENTIFIED BY 'testpassword';
Пользователю с логином testuser
и паролем testpassword
предоставили полные права доступа к базе solar_system
.
Теперь создадим таблицу и заполним данными, астрономическая точность которых не подразумевается:
USE solar_system;
CREATE TABLE planets (
id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
name VARCHAR(10) NOT NULL,
color VARCHAR(10) NOT NULL
);
INSERT INTO planets(name, color) VALUES('earth', 'blue'), ('mars', 'red'), ('jupiter', 'strange');
Описание соединения
Теперь, когда создана база, определим DSN (Data Source Name) — сведения для подключения к базе, представленные в виде строки. Синтаксис описания отличается в зависимости от используемой СУБД. В примере работаем с MySQL/MariaDB, поэтому указываем:
- тип драйвера;
- имя хоста, где расположена СУБД;
- порт (необязательно, если используется стандартный порт
3306
); - имя базы данных;
- кодировку (необязательно).
Строка DSN в этом случае выглядит следующим образом:
$dsn = "mysql:host=localhost;port=3306;dbname=solar_system;charset=utf8";
Первым указывается database prefix
. В примере — mysql
. Префикс отделяется от остальной части строки двоеточием, а каждый следующий параметр — точкой с запятой.
Теперь, когда строка DSN готова, создадим PDO-объект. Конструктор на входе принимает следующие параметры:
- Строку DSN.
- Имя пользователя, имеющего доступ к базе данных.
- Пароль этого пользователя.
- Массив с дополнительными параметрами (необязательно).
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
$pdo = new PDO($dsn, 'testuser', 'testpassword', $options);
Дополнительные параметры можно также определить после создания объекта с помощью метода SetAttribute
:
$pdo->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Определение метода выборки по умолчанию
PDO::DEFAULT_FETCH_MODE
— важный параметр, который определяет метод выборки по умолчанию. Указанный метод используется при получении результата выполнения запроса.
PDO::FETCH_BOTH
Режим по умолчанию. Результат выборки индексируется как номерами (начиная с 0), так и именами столбцов:
$stmt = $pdo->query("SELECT * FROM planets");
$results = $stmt->fetch(PDO::FETCH_BOTH);
После выполнения запроса с этим режимом к тестовой таблице планет получим следующий результат:
Array
(
[id] => 1
[0] => 1
[name] => earth
[1] => earth
[color] => blue
[2] => blue
)
PDO::FETCH_ASSOC
Результат сохраняется в ассоциативном массиве, в котором ключ — имя столбца, а значение — соответствующее значение строки:
$stmt = $pdo->query("SELECT * FROM planets");
$results = $stmt->fetch(PDO::FETCH_ASSOC);
В результате получим:
Array
(
[id] => 1
[name] => earth
[color] => blue
)
PDO::FETCH_NUM
При использовании этого режима результат представляется в виде массива, индексированного номерами столбцов (начиная с 0):
Array
(
[0] => 1
[1] => earth
[2] => blue
)
PDO::FETCH_COLUMN
Этот вариант полезен, если нужно получить перечень значений одного поля в виде одномерного массива, нумерация которого начинается с 0. Например:
$stmt = $pdo->query("SELECT name FROM planets");
В результате получим:
Array
(
[0] => earth
[1] => mars
[2] => jupiter
)
PDO::FETCH_KEY_PAIR
Используем этот вариант, если нужно получить перечень значений двух полей в виде ассоциативного массива. Ключи массива — это данные первого столбца выборки, значения массива — данные второго столбца. Например:
$stmt = $pdo->query("SELECT name, color FROM planets");
$result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
В результате получим:
Array
(
[earth] => blue
[mars] => red
[jupiter] => strange
)
PDO::FETCH_OBJECT
При использовании PDO::FETCH_OBJECT
для каждой извлеченной строки создаётся анонимный объект. Его общедоступные (public) свойства — имена столбцов выборки, а результаты запроса используются в качестве их значений:
$stmt = $pdo->query("SELECT name, color FROM planets");
$results = $stmt->fetch(PDO::FETCH_OBJ);
В результате получим:
stdClass Object
(
[name] => earth
[color] => blue
)
PDO::FETCH_CLASS
В этом случае, как и в предыдущем, значения столбцов становятся свойствами объекта. Однако требуется указать существующий класс, который будет использоваться для создания объекта. Рассмотрим это на примере. Для начала создадим класс:
class Planet
{
private $name;
private $color;
public function setName($planet_name)
{
$this->name = $planet_name;
}
public function setColor($planet_color)
{
$this->color = $planet_color;
}
public function getName()
{
return $this->name;
}
public function getColor()
{
return $this->color;
}
}
Обратите внимание, что у класса Planet
закрытые (private) свойства и нет конструктора. Теперь выполним запрос.
Если используется метод fetch
с PDO::FETCH_CLASS
, перед отправкой запроса на получение данных нужно применить метод setFetchMode
:
$stmt = $pdo->query("SELECT name, color FROM planets");
$stmt->setFetchMode(PDO::FETCH_CLASS, 'Planet');
Первый параметр, который передаем методу setFetchMode
, — константа PDO::FETCH_CLASS
. Второй параметр — имя класса, который будет использоваться при создании объекта. Теперь выполним:
$planet = $stmt->fetch();
var_dump($planet);
В результате получим объект Planet
:
Planet Object
(
[name:Planet:private] => earth
[color:Planet:private] => blue
)
Значения, полученные в результате запроса, назначены соответствующим свойствам объекта, даже закрытым.
Определение свойств после выполнения конструктора
В классе Planet
нет явного конструктора, поэтому проблем при назначении свойств не будет. При наличии у класса конструктора, в котором свойство было назначено или изменено, они будут перезаписаны.
При использовании константы FETCH_PROPS_LATE
значения свойств будут присваиваться после выполнения конструктора:
class Planet
{
private $name;
private $color;
public function __construct($name = moon, $color = grey)
{
$this->name = $name;
$this->color = $color;
}
public function setName($planet_name)
{
$this->name = $planet_name;
}
public function setColor($planet_color)
{
$this->color = $planet_color;
}
public function getName()
{
return $this->name;
}
public function getColor()
{
return $this->color;
}
}
Мы изменили класс Planet
, добавив конструктор, который принимает на входе два аргумента: name
(имя) и color
(цвет). Значения этих полей по умолчанию: moon
(луна) и gray
(серый) соответственно.
Если не использовать FETCH_PROPS_LATE
, при создании объекта свойства будут перезаписаны значениями по умолчанию. Проверим это. Сначала выполним запрос:
$stmt = $pdo->query("SELECT name, color FROM solar_system WHERE name = 'earth'");
$stmt->setFetchMode(PDO::FETCH_CLASS, 'Planet');
$planet = $stmt->fetch();
var_dump($planet);
В результате получим:
object(Planet)#2 (2) {
["name":"Planet":private]=>
string(4) "moon"
["color":"Planet":private]=>
string(4) "gray"
}
Как и ожидалось, извлеченные из базы данных значения перезаписаны. Теперь рассмотрим решение задачи с помощью FETCH_PROPS_LATE
(запрос аналогичный):
$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'Planet');
$planet = $stmt->fetch();
var_dump($planet);
В результате получим то, что нужно:
object(Planet)#4 (2) {
["name":"Planet":private]=>
string(5) "earth"
["color":"Planet":private]=>
string(4) "blue"
}
Если у конструктора класса нет значений по умолчанию, а они нужны, параметры конструктора задаются при вызове метода setFetchMode
третьим аргументом в виде массива. Например:
class Planet
{
private $name;
private $color;
public function __construct($name, $color)
{
$this->name = $name;
$this->color = $color;
}
[...]
}
Аргументы конструктора обязательны, поэтому выполним:
$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'Planet', ['moon', 'gray']);
Входящие параметры выступают также в роли значений по умолчанию, которые нужны для инициализации. В дальнейшем они будут перезаписаны значениями из базы данных.
Получение нескольких объектов
Множественные результаты извлекаются в виде объектов с помощью метода fetch
внутри цикла while
:
while ($planet = $stmt->fetch()) {
// обработка результатов
}
Или путём выборки всех результатов сразу. Во втором случае используется метод fetchAll
, причём режим указывается в момент вызова:
$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, 'Planet', ['moon', 'gray']);
PDO::FETCH_INTO
При выборе этого варианта выборки PDO не создаёт новый объект, а обновляет свойства существующего. Однако это возможно только для общедоступных (public) свойств или при использовании в объекте «магического» метода __set
.
Подготовленные и прямые запросы
В PDO два способа выполнения запросов:
- прямой, который состоит из одного шага;
- подготовленный, который состоит из двух шагов.
Прямые запросы
Существует два метода выполнения прямых запросов:
query
используется для операторов, которые не вносят изменения, напримерSELECT
. Возвращает объектPDOStatemnt
, из которого с помощью методовfetch
илиfetchAll
извлекаются результаты запроса;exec
используется для операторов вродеINSERT
,DELETE
илиUPDATE
. Возвращает число обработанных запросом строк.
Прямые операторы используются только в том случае, если в запросе отсутствуют переменные и есть уверенность, что запрос безопасен и правильно экранирован.
Подготовленные запросы
PDO поддерживает подготовленные запросы (prepared statements), которые полезны для защиты приложения от SQL-инъекций: метод prepare
выполняет необходимые экранирования.
Рассмотрим пример. Требуется вставить свойства объекта Planet
в таблицу Planets
. Сначала подготовим запрос:
$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(?, ?)");
Используем метод prepare
, который принимает как аргумент SQL-запрос с псевдопеременными (placeholders). Псевдопеременные могут быть двух типов: неименнованые и именованные.
Неименованные псевдопеременные
Неименованные псевдопеременные (positional placeholders) отмечаются символом ?
. Запрос в результате получается компактным, но требуется предоставить значения для подстановки, размещенные в том же порядке. Они передаются в виде массива через метод execute
:
$stmt->execute([$planet->name, $planet->color]);
Именованные псевдопеременные
При использовании именованных псевдопеременных (named placeholders) порядок передачи значений для подстановки не важен, но код в этом случае становится не таким компактным. В метод execute
данные передаются в виде ассоциативного массива, в котором каждый ключ соответствует имени псевдопеременной, а значение массива — значению, которое требуется подставить в запрос. Переделаем предыдущий пример:
$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(:name, :color)");
$stmt->execute(['name' => $planet->name, 'color' => $planet->color]);
Методы prepare
и execute
используются как при выполнении запросов на изменение, так и при выборке.
А информацию о количестве обработанных строк при необходимости предоставит метод rowCount
.
Параметр выбора режима ошибок PDO::ATTR_ERRMODE
используется для определения поведения PDO в случае ошибок. Доступно три варианта: PDO::ERRMODE_SILENT
, PDO::ERRMODE_EXCEPTION
и PDO::ERRMODE_WARNING
.
PDO::ERRMODE_SILENT
Вариант по умолчанию. PDO просто запишет информацию об ошибке, которую помогут получить методы errorCode и errorInfo.
PDO::ERRMODE_EXCEPTION
Это предпочтительный вариант, при котором в дополнение к информации об ошибке PDO выбрасывает исключение (PDOException). Исключение прерывает выполнение скрипта, что полезно при использовании транзакций PDO. Пример приведён ниже при описании транзакций.
PDO::ERRMODE_WARNING
В этом случае PDO также записывает информацию об ошибке. Поток выполнения скрипта не прерывается, но выдаются предупреждения.
Методы bindValue и bindParam
Для подстановки значений в запросе можно также использовать методы bindValue
и bindParam
. Первый связывает значение переменной с псевдопеременной, которая использована при подготовке запроса:
$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(:name, :color)");
$stmt->bindValue('name', $planet->name, PDO::PARAM_STR);
Связали значение переменной $planet->name
с псевдопеременной :name
. Обратите внимание, что при использовании методов bindValue
и bindParam
как третий аргумент указывается тип переменной, используя соответствующие константы PDO. В примере — PDO::PARAM_STR
.
Метод bindParam
привязывает переменную к псевдопеременной. В этом случае переменная связана с псевдопеременной ссылкой, а значение будет подставлено в запрос только после вызова метода execute
. Рассмотрим на примере:
$stmt->bindParam('name', $planet->name, PDO::PARAM_STR);
Транзакции в PDO
Транзакции позволяют сохранить на некоторое время и организовать выполнение нескольких запросов «пакетом». Запросы, включённые в транзакцию, применяются только в том случае, если при выполнении отсутствуют ошибки. Транзакции поддерживаются не всеми СУБД и работают не со всеми SQL-конструкциями, так как некоторые из них вызывают неявное выполнение. Список таких конструкций можно найти на сайте MariaDB.
Представим необычный пример. Пользователю требуется выбрать список планет, причём каждый раз при выполнении запроса текущие данные удаляются из базы, а потом вставляются новые. Если после удаления произойдёт ошибка, то следующий пользователь получит пустой список. Чтобы этого избежать, используем транзакции:
$pdo->beginTransaction();
try {
$stmt1 = $pdo->exec("DELETE FROM planets");
$stmt2 = $pdo->prepare("INSERT INTO planets(name, color) VALUES (?, ?)");
foreach ($planets as $planet) {
$stmt2->execute([$planet->getName(), $planet->getColor()]);
}
$pdo->commit();
} catch (PDOException $e) {
$pdo->rollBack();
}
Метод beginTransaction
отключает автоматическое выполнение запросов, а внутри конструкции try-catch
запросы выполняются в нужном порядке. Если не возникнет исключений PDOException
, запросы выполнятся с помощью метода commit
. В противном случае откатятся с помощью метода rollback
, а автоматическое выполнение запросов восстановится.
Таким образом появилась согласованность выполнения запросов. Очевидно, что для этого параметру PDO::ATTR_ERRMODE
необходимо установить значение PDO::ERRMODE_EXCEPTION
.
Заключение
Теперь, когда работа с PDO описана, отметим его основные преимущества:
- с PDO легко перенести приложение на другие СУБД;
- поддерживаются все популярные СУБД;
- встроенная система управления ошибками;
- разнообразные варианты представления результатов выборки;
- поддерживаются подготовленные запросы, которые сокращают код и делают его устойчивым к SQL-инъекциям;
- поддерживаются транзакции, которые помогают сохранить целостность данных и согласованность запросов при параллельной работе пользователей.
Перевод статьи «How to configure and use PDO for database access on Linux»
В этой статье разговор пойдет о PHP Data Objects (PDO) — расширение для PHP, предоставляющее разработчику универсальный интерфейс для доступа к различным базам данных.
В чем преимущество PDO? Этот вопрос можно раскрыть тремя пунктами:
- Универсальный интерфейс для работы с различными базами данных. Разработчик может легко перевести свое веб-приложение на другую СУБД, поменяв при этом всего пару строк кода.
- Высокая скорость работы.
- Подготовленные выражения, о которых мы поговорим чуть позже.
На данный момент расширение PDO может поддерживать СУБД для которой существует PDO-драйвер:
- PDO_CUBRID (CUBRID)
- PDO_DBLIB (FreeTDS, Microsoft SQL Server, Sybase)
- PDO_FIREBIRD (Firebird, Interbase 6)
- PDO_IBM (IBM DB2)
- PDO_INFORMIX (IBM Informix Dynamic Server)
- PDO_MYSQL (MySQL 3.x/4.x/5.x)
- PDO_OCI (Oracle Call Interface)
- PDO_ODBC (ODBC v3 (IBM DB2, unixODBC and win32 ODBC))
- PDO_PGSQL (PostgreSQL)
- PDO_SQLITE (SQLite 3 and SQLite 2)
- PDO_SQLSRV (Microsoft SQL Serve )
- PDO_4D (4D)
Подключение к базе данных
В зависимости от выбранной СУБД, способ подключения может незначительно отличаться. Подключение к популярным СУБД:
// MуSQL $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); // PostgreSQL $DBH = new PDO("pgsql:host=$host;dbname=$dbname", $user, $pass); //MS SQL $DBH = new PDO("mssql:host=$host;dbname=$dbname", $user, $pass); // SQLite $DBH = new PDO("sqlite:my/database/path/database.db");
Обработка ошибок и исключения
Обязательно заключайте подключение к базе данных в блок try/catch:
try { $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); } catch(PDOException $e) { echo "Нет соединения с базой данных"; }
Иначе, в случае ошибки, в браузер будет выкинут Fatal error, в котором будут раскрыты все подробности вашего соединения, с логином и паролем.
PDO умеет выбрасывать исключения при ошибках, поэтому все операции с базой, по хорошему, должны находиться в блоке try/catch.
PDO имеет три режима обработки исключения:
- PDO::ERRMODE_SILENT — режим по умолчанию, ошибки генерируются по такому же принципу, как в расширениях mysql или mysqli. После возникновения ошибки скрипт продолжит работу.
- PDO::ERRMODE_WARNING — режим вызовет стандартное сообщение E_WARNING и позволит скрипту продолжить работу.
- PDO::ERRMODE_EXCEPTION — режим выбрасывает исключение, что позволяет обрабатывать ошибки и скрывать важную информацию от посторонних глаз.
Чтобы установить необходимый уровень контроля ошибок необходимо вызвать метод $this->setAttribute после подключения к базе данных.
try { $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e) { echo "Нет соединения с базой данных"; }
Подготовленные выражения или Prepared Statements
Подготовленные выражения — это заранее скомпилированное SQL-выражение, которое может быть многократно выполнено путем отправки серверу лишь различных наборов данных. Дополнительным преимуществом является невозможность провести SQL-инъекцию.
За подготовленные выражения отвечает метод $DBH->prepare. Им и рекомендуется всегда пользоваться.
Сразу хочу отметить, что выполнить запрос в PDO можно тремя методами:
- $DBH->exec — используется для запросов, которые не возвращают никаких данных. Метод возвращает количество затронутых им записей, или FALSE в случае ошибки.
$count_row = $DBH->exec("DELETE FROM users");
- $DBH->query – используется выполнения не защищенных запросов, и возвращает результат или FALSE в случаи ошибки. Например, им можно выполнять простые запросы.
$DBH->query("SET NAMES 'cp1251'"); $DBH->query("SELECT * FROM users"); $DBH->query("DELETE FROM users");
- $DBH->prepare + $STH->execute — используется для подготовки выражений и выполнения запроса.
// безымянные placeholders $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (?, ?, ?)");
// именные placeholders $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (:name, :phone, :city)");
После подготовки, запрос выполняется методом $STH->execute($data).
// безымянные placeholders $data = array(); $data[] = 'Alersander'; $data[] = '+7 000 123 45 67'; $data[] = 'St. Petersburg'; $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (?, ?, ?)"); $STH->execute($data);
// именные placeholders $data = array(); $data['name'] = 'Alersander'; $data['phone'] = '+7 000 123 45 67'; $data['city'] = 'St. Petersburg'; $STH = $DBH->prepare("INSERT INTO users (name, phone, city) values (:name, :phone, :city)"); $STH->execute($data);
Выборка данных
Для выборки с произвольными параметрами тоже будем использовать метод $DBH->prepare. Данные выборки можно получить с помощью методов:
- $STH->fetch — выбирает следующую строку и возвращает в необходимом виде.
- $STH->fetchAll — возвращает массив всех выбранных строк.
- $STH->fetchObject — выбирает следующую строку и возвращает ее как объект.
Я буду рассматривать только первый метод, т.к. он универсальный и предоставляет разработчику, всё, что ему необходимо.
Методу $STH->fetch можно указать, в каком виде нам нужно предоставить результат:
- PDO::FETCH_BOTH (по умолчанию) — возвращает числовой и ассоциативный массив;
- PDO::FETCH_ASSOC — возвращает массив ассоциативный с названиями столбцов;
- PDO::FETCH_NUM — возвращает массив числовыми ключами в виде порядковых номеров столбцов;
- PDO::FETCH_OBJ — возвращает анонимный объект со свойствами, соответствующими именам столбцов;
- PDO::FETCH_BOUND — присваивает значения столбцов соответствующим переменным, заданным с помощью метода $STH->bindColumn();
- PDO::FETCH_CLASS — присваивает значения столбцов соответствующим свойствам указанного класса. Если для какого-то столбца свойства нет, оно будет создано;
- PDO::FETCH_INTO — обновляет существующий экземпляр указанного класса;
- PDO::FETCH_LAZY — объединяет в себе PDO::FETCH_BOTH и PDO::FETCH_OBJ.
$STH = $DBH->prepare("SELECT name, phone, city FROM users"); $STH->execute(); while($res = $STH->fetch(PDO::FETCH_ASSOC)) { echo $res['name']; } $STH = $DBH->prepare("SELECT name, phone, city FROM users"); $STH->execute(); while($res = $STH->fetch(PDO::FETCH_OBJ)) { echo $res->name; }
Закрытие соединения и освобождение буфера запроса
В PDO нет специальных методов для этих целей. Закрыть соединение с базой данных можно путем переопределения переменных:
$DBH = null; $STH = null;
Полезные методы
- $DBH->lastInsertId() — возвращает id последней вставленной записи.
- $DBH->query(string) — экранирует специальные символы в строковых данных таким образом, что их становится безопасно использовать в запросах.
- $STH->rowCount() — возвращает количество затронутых записей последним запросом.
Обработка ошибок PDO
Лично мне не нравится, что если я не заключаю все запросы в блок try/catch, то PDO выкидывает Fatal error со всеми интимными подробностями моего запроса. В промышленном приложении заключать каждый запрос в блок try/catch, это идиотизм!
Поэтому мы поступим следующим образом — немного расширим классы PDO и PDOStatement:
class DB extends PDO { public $error = false; // выводить сообщения об ошибках на экран? (true/false) public function __construct($dsn, $username='', $password='', $driver_options=array()) { try { parent::__construct($dsn, $username, $password, $driver_options); $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DBStatement', array($this))); $this->query("SET NAMES 'cp1251'"); } catch(PDOException $e) { echo "Произошла ошибка в работе с базой данных..."; exit(); } } public function prepare($sql, $driver_options=array()) { try { return parent::prepare($sql, $driver_options); } catch(PDOException $e) { $this->error($e->getMessage()); } } public function query($sql) { try { return parent::query($sql); } catch(PDOException $e) { $this->error($e->getMessage()); } } public function exec($sql) { try { return parent::exec($sql); } catch(PDOException $e) { $this->error($e->getMessage()); } } public function error($msg) { if($this->error) { echo $msg; } else { echo "Произошла ошибка в работе с базой данных..."; } exit(); } }
class DBStatement extends PDOStatement { protected $DBH; protected function __construct($DBH) { $this->DBH = $DBH; } public function execute($data=array()) { try { return parent::execute($data); } catch(PDOException $e) { $this->DBH->error($e->getMessage()); } } }
Как видите, я реализую свои два класса DB и DBStatement, наследуя классы PDO и PDOStatement. Классы реализуют все необходимые мне для работы над ошибками методы, которые обрабатываются блоком try/catch.
$DBH = new DB("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->error = true; // Для отладки выводим сообщения об ошибках на экран. $STH = $DBH->prepare("SELEC * FROM users"); $STH->execute($data);
Как видите, я совершил опечатку в операторе и могу получить всю необходимую информацию об этой ошибке.
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELEC * FROM users' at line 1
Расширение функционала
Также бывает полезно расширить функционал PDO. Например, часто требуется получить количество записей в таблице.
Стандартными методами это можно делать следующим образом:
$data = array(); $data['user_id'] = 1; $STH = $DBH->prepare("SELECT COUNT(*) as count FROM users WHERE user_id=:user_id"); $STH->execute($data); echo $STH->fetch(PDO::FETCH_OBJ)->count;
Не слишком удобно. Поэтому реализуем в нашем классе методом count:
class DB extends PDO { // .................. public function count($sql, $data) { $res = $this->prepare($sql); $res->execute($data); return $res->fetch(PDO::FETCH_OBJ); } // .................. }
Получаем количество записей:
$DBH = new DB("mysql:host=$host;dbname=$dbname", $user, $pass); echo $DBH->count("SELECT COUNT(*) as count FROM users WHERE user_id=:user_id", array('user_id'=>'1'))->count;
Свои методы это конечно хорошо, но мне бы ещё хотелось писать все одной строкой. К сожалению, стандартными возможностями я не могу этого сделать:
$res = $DBH->prepare("SELECT * FROM users WHERE id_user=:id_user") ->execute(array('id_user'=>'1')) ->fetch(PDO::FETCH_ASSOC); echo $res['name']; // или так echo $DBH->prepare("SELECT *FROM users WHERE id_user=:id_user") ->execute(array('id_user'=>'1')) ->fetch(PDO::FETCH_OB) ->name;
Метод execute возвращает бесполезное логическое значение об успехе операции, а не объект DBStatement.
Допиливаем свой метод execute:
public function execute($data=array()) { try { parent::execute($data); return $this; } catch(PDOException $e) { $this->DBH->error($e->getMessage()); } }
Проверяем результат:
echo $DBH->prepare("SELECT COUNT(*) as count FROM users WHERE city=:city") ->execute(array('city'=>'St. Petersburg')) ->fetch(PDO::FETCH_OBJ) ->count;
Источник
Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
PDO::errorInfo
(PHP 5 >= 5.1.0, PHP 7, PECL pdo >= 0.1.0)
PDO::errorInfo —
Получает расширенную информацию об ошибке, произошедшей в ходе
последнего обращения к базе данных
Описание
public PDO::errorInfo
( void
) : array
Возвращаемые значения
PDO::errorInfo() возвращает массив с информацией об ошибке,
произошедшей в ходе выполнения последней операции с базой данных. Массив
содержит как минимум следующие поля:
Элемент | Информация |
---|---|
0 | Код ошибки SQLSTATE (пятисимвольный идентификатор, определенный в стандарте ANSI SQL). |
1 | Код ошибки, заданный драйвером. |
2 | Сообщение об ошибке, заданное драйвером |
Замечание:
Если не задан SQLSTATE код или драйвер не сообщил об ошибке, то элементы
следующие за нулевым будут иметь значениеNULL
.
PDO::errorInfo() выдает информацию об ошибке только для операций,
совершаемых с базой данных напрямую из PDO. Если создать объект PDOStatement
методами PDO::prepare() или
PDO::query(), и вызвать ошибку его методами,
PDO::errorInfo() эту ошибку не отобразит. Вам нужно вызвать
PDOStatement::errorInfo(), чтобы получить информации об ошибках для операции,
выполняемой на определенном объекте PDOStatement.
Примеры
Пример #1
Вывод полей массива errorInfo() для PDO_ODBC подключения к базе данных DB2
<?php
/* Спровоцируем синтаксическую ошибку SQL */
$stmt = $dbh->prepare('bogus sql');
if (!$stmt) {
echo "nPDO::errorInfo():n";
print_r($dbh->errorInfo());
}
?>
Результат выполнения данного примера:
PDO::errorInfo(): Array ( [0] => HY000 [1] => 1 [2] => near "bogus": syntax error )
Смотрите также
- PDO::errorCode() — Возвращает код SQLSTATE результата последней операции с базой данных
- PDOStatement::errorCode() — Получает код SQLSTATE, связанный с последней операцией в объекте PDOStatement
- PDOStatement::errorInfo() — Получение расширенной информации об ошибке, произошедшей в результате работы
объекта PDOStatement