Как использовать PDO в PHP для работы с MySQL и другими СУБД

PDO — это лёгкий, унифицированный интерфейс для работы с разными СУБД в PHP. Он не заменяет драйвер базы, а предоставляет общий набор методов для подключения, выполнения запросов и работы с результатами, что упрощает переносимость кода между базами.
Почему стоит выбрать PDO
- Единый API для разных СУБД (MySQL, PostgreSQL, SQLite и др.).
- Поддержка подготовленных выражений (prepared statements) — главная защита от SQL-инъекций и удобство повторного выполнения запросов.
- Управление транзакциями, режимы ошибок и гибкие режимы извлечения данных.
Быстрое подключение (DSN, конструктор и опции)
Подключение создаётся через конструктор PDO, в котором первым параметром идёт DSN (Data Source Name), затем пользователь и пароль, а также опции.
Prepared statements работают в две фазы: подготовка (prepare) и выполнение (execute). Это позволяет безопасно подставлять значения в запрос и избегать ручной экранизации. PDO может эмулировать подготовленные выражения, если драйвер их не поддерживает.
Важно: нельзя смешивать в одном SQL-шаблоне позиционные и именованные плейсхолдеры — это вызовет ошибку. (Выбирайте один стиль для запроса.)
Привязка параметров: bindParam vs bindValue
bindValue($param, $value, $type) — привязывает значение сразу. Полезно для литералов.
bindParam($param, $var, $type) — привязывает переменную по ссылке; значение будет прочитано при execute() (удобно, если переменная меняется перед выполнением).
$stmt = $pdo->prepare('UPDATE accounts SET balance = :bal WHERE id = :id');
$stmt->bindValue(':bal', 100.5, PDO::PARAM_STR);
$stmt->bindValue(':id', 42, PDO::PARAM_INT);
$stmt->execute();
PDO::FETCH_ASSOC — ассоц. массив (['id'=>1, 'name'=>'x'])
PDO::FETCH_NUM — нумерованный массив
PDO::FETCH_OBJ — объект ($row->name)
PDO::FETCH_CLASS — заполнить экземпляр класса
Обработка ошибок и режимы ошибок
Рекомендуется использовать режим PDO::ERRMODE_EXCEPTION — тогда PDO бросает PDOException, и ошибки легче отлавливать и логировать. Альтернативы: PDO::ERRMODE_SILENT (по умолчанию) и PDO::ERRMODE_WARNING.
Небольшие советы по безопасности и стабильности
- Всегда используйте подготовленные выражения для подстановки пользовательских данных.
- Выключайте эмуляцию подготовленных выражений (PDO::ATTR_EMULATE_PREPARES => false) при работе с MySQL, если хотите, чтобы драйвер использовал нативные prepared statements (иногда это важно для типов данных и производительности).
- Устанавливайте charset в DSN (charset=utf8mb4 для MySQL), чтобы избежать проблем с кодировкой.
- Логируйте ошибки, но не выводите детальные сообщения с SQL в публичный интерфейс.
Общие ошибки и ловушки
-
Смешивание именованных и позиционных плейсхолдеров в одном запросе.
-
Ожидание, что PDO сам по-умолчанию бросает исключения (нужно явно установить ATTR_ERRMODE).
-
Использование exec() вместо prepare/execute() для запросов с пользовательскими данными — риск инъекций.
Мини-класс-обёртка (простой и безопасный пример)
<?php
class DB {
private static ?PDO $pdo = null;
public static function getPDO(): PDO {
if (self::$pdo === null) {
$dsn = 'mysql:host=127.0.0.1;dbname=testdb;charset=utf8mb4';
$opts = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
self::$pdo = new PDO($dsn, 'dbuser', 'dbpass', $opts);
}
return self::$pdo;
}
public static function fetchAll(string $sql, array $params = []): array {
$stmt = self::getPDO()->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
}
Короткое резюме (что важно помнить)
PDO — универсальный, безопасный и гибкий инструмент для работы с БД в PHP. Используйте подготовленные выражения и режим ошибок ERRMODE_EXCEPTION. Транзакции — для атомарных операций; всегда оборачивайте в try/catch и откатывайте при ошибке.
Чтобы получить полный доступ, зарегистрируйтесь или войдите под своим именем.
