PDO в PHP — подключение и безопасные запросы
PDO (PHP Data Objects) — единый интерфейс доступа к разным СУБД через драйверы (pdo_mysql, pdo_pgsql, pdo_sqlite). Это выжимка для старта; расширенный разбор ORM, MySQLi и оптимизации — в Работа с базами данных из PHP.
Подключение
<?php
declare(strict_types=1);
$dsn = 'mysql:host=127.0.0.1;dbname=app;charset=utf8mb4';
$user = 'app_user';
$pass = 'secret';
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
| Параметр | Назначение |
|---|---|
ERRMODE_EXCEPTION | Ошибки SQL → PDOException, а не тихий сбой |
FETCH_ASSOC | Строки как ассоциативные массивы |
EMULATE_PREPARES false | Настоящие prepared statements на стороне MySQL |
DSN для SQLite (удобно для учебных проектов без сервера MySQL):
$pdo = new PDO('sqlite:' . __DIR__ . '/data/app.sqlite', options: [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
Учётные данные хранят в переменных окружения или .env, не в репозитории.
Подготовленные запросы
Плейсхолдеры ? или именованные :name отделяют структуру SQL от данных. Это основная защита от SQL-инъекций.
$stmt = $pdo->prepare('SELECT id, email FROM users WHERE email = :email LIMIT 1');
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();
if ($user === false) {
// не найден
}
Вставка:
$stmt = $pdo->prepare(
'INSERT INTO users (email, name, created_at) VALUES (:email, :name, :created_at)'
);
$stmt->execute([
'email' => $email,
'name' => $name,
'created_at' => (new DateTimeImmutable())->format('Y-m-d H:i:s'),
]);
$newId = (int) $pdo->lastInsertId();
Нельзя подставлять имена таблиц и колонок через плейсхолдеры — только значения. Для динамических имён — белый список в коде.
Выборка нескольких строк
$stmt = $pdo->prepare('SELECT id, title FROM posts WHERE user_id = :uid ORDER BY id DESC');
$stmt->execute(['uid' => $userId]);
$posts = $stmt->fetchAll();
Итерация без загрузки всего результата в память (большие таблицы):
$stmt = $pdo->query('SELECT id, body FROM logs'); // только доверенный SQL без пользовательских частей
while ($row = $stmt->fetch()) {
processLogLine($row);
}
Обновление и удаление
$stmt = $pdo->prepare('UPDATE users SET name = :name WHERE id = :id');
$stmt->execute(['name' => $name, 'id' => $id]);
$updated = $stmt->rowCount();
$stmt = $pdo->prepare('DELETE FROM sessions WHERE expires_at < :now');
$stmt->execute(['now' => date('Y-m-d H:i:s')]);
rowCount() для SELECT в MySQL может вести себя неинтуитивно; для проверки «есть ли строка» надёжнее fetch().
Транзакции
Группа операций «всё или ничего»:
$pdo->beginTransaction();
try {
$pdo->prepare('UPDATE accounts SET balance = balance - :sum WHERE id = :id')
->execute(['sum' => $sum, 'id' => $fromId]);
$pdo->prepare('UPDATE accounts SET balance = balance + :sum WHERE id = :id')
->execute(['sum' => $sum, 'id' => $toId]);
$pdo->commit();
} catch (Throwable $e) {
$pdo->rollBack();
throw $e;
}
При ERRMODE_EXCEPTION сбой execute прерывает блок и уходит в catch.
Обработка ошибок
try {
$pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
// ...
} catch (PDOException $e) {
error_log('Database: ' . $e->getMessage());
http_response_code(503);
echo 'Сервис временно недоступен';
}
Детали подключения (пароль, хост) не показывают пользователю. См. Исключения в прикладном коде.
PDO и MySQLi
| PDO | MySQLi | |
|---|---|---|
| СУБД | MySQL, PostgreSQL, SQLite, … | В основном MySQL |
| Стиль | Один API для всех | Процедурный и ООП |
| Подготовленные запросы | Да | Да |
Для новых проектов на MySQL чаще выбирают PDO из-за единообразия и переносимости. MySQLi остаётся в легаси и узкоспециализированных случаях — см. полный раздел по БД.
Чек-лист перед продакшеном
ATTR_ERRMODE = EXCEPTION- Все пользовательские значения — только через
prepare+execute - Кодировка
utf8mb4в DSN MySQL - Отдельный пользователь БД с минимальными правами (не
root) - Пароль и DSN — из окружения, не из git
Что изучить дальше
- От формы до записи в БД — сквозной пример
- Работа с данными со страницы
- Работа с базами данных из PHP
- Исключения
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). PHP как язык веб-разработки - роль серверного исполнения, базовый синтаксис и место в современном стеке. Экосистема PHP-приложений - фреймворки, инструменты, пакеты и типовые архитектурные подходы веб-разработки. PHP — это язык программирования общего назначения, который изначально создавался для динамической генерации веб-страниц. Модель исполнения PHP - жизненный цикл запроса, серверный контекст и экосистема популярных CMS. История PHP - эволюция языка от простых скриптов до зрелой платформы серверной веб-разработки. Composer в PHP - управление зависимостями, автозагрузка классов и воспроизводимая сборка проектов. Параметр opcache.fast_shutdown ускоряет завершение работы скрипта за счёт пропуска стандартной процедуры освобождения памяти. Вместо этого используется механизм сборщика мусора операционной системы. Локальная среда разработки на PHP - настройка стека, запуск приложения и отладка без продакшен-сервера. Набор советов, правил, принципов и обычаев в разработке на этом языке. Фреймворки и библиотеки PHP - организация сервисов, вспомогательные компоненты и ускорение разработки веб-приложений. Гайд по установке и настройке с написанием первой программы и её запуском. Примеры простых и полезных консольных приложений с демонстрацией концепций языка.PHP - язык веб-разработки
Экосистема PHP-приложений
Что требуется знать перед началом изучения языка программирования PHP
Модель исполнения PHP
История языка PHP
Composer - управление зависимостями в PHP
Настройка веб-сервера для работы с PHP
Локальная среда разработки на PHP
Рекомендации по разработке на PHP
Фреймворки и библиотеки PHP
Первая программа на PHP
Простые приложения на PHP