🧱 Суть
PDO (PHP Data Objects) – это встроенный в PHP интерфейс для работы с базами данных.
Он позволяет:
- подключаться к базе данных
- выполнять SQL-запросы
- получать результаты
- отправлять параметры безопасным способом
Схема работы:
PHP-приложение
|
| PDO
↓
База данных
|
↓
MySQL / PostgreSQL / SQLitePDO работает через драйверы, поэтому один и тот же код можно использовать с разными СУБД.
Пример:
new PDO(
"mysql:host=localhost;dbname=test",
"root",
"password"
);📦 Проблема
1. Нельзя вставлять данные пользователя напрямую в SQL
Плохо:
$id = $_GET['id'];
$sql = "
SELECT *
FROM users
WHERE id = $id
";Если пользователь отправит:
?id=1 OR 1=1Получится:
SELECT *
FROM users
WHERE id = 1 OR 1=1Это SQL-инъекция.
2. SQL-запросы могут содержать повторяющийся код
Без отдельного слоя работы с БД появляются:
- дублирование подключения
- повторение запросов
- сложное изменение базы данных
3. Нужно правильно обрабатывать ошибки
Ошибки базы данных могут содержать:
- структуру таблиц
- SQL-запросы
- внутреннюю информацию
Их нельзя просто показывать пользователю.
✅ Решение
Использовать:
- PDO для подключения
- подготовленные запросы (
prepare) - параметры (
bind) - обработку исключений
💻 Код
Подключение к базе данных
Создание подключения:
$pdo = new PDO(
'mysql:host=localhost;dbname=test;charset=utf8mb4',
'root',
'password'
);Параметры:
| Часть | Значение |
|---|---|
mysql | драйвер БД |
host | сервер базы |
dbname | имя базы |
charset | кодировка |
Настройка PDO
Обычно сразу включают режим исключений:
$pdo = new PDO(
'mysql:host=localhost;dbname=test;charset=utf8mb4',
'root',
'password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]
);Теперь ошибки будут выбрасываться как:
PDOExceptionSELECT-запросы
Пример:
SELECT *
FROM users;В PHP:
$stmt = $pdo->query(
'SELECT * FROM users'
);
$users = $stmt->fetchAll();Результат:
[
[
'id' => 1,
'name' => 'Alex'
]
]Получение одной записи
$stmt = $pdo->query(
'SELECT * FROM users LIMIT 1'
);
$user = $stmt->fetch();Типы получения данных
Ассоциативный массив
$user = $stmt->fetch(
PDO::FETCH_ASSOC
);Результат:
[
'id' => 1,
'name' => 'Alex'
]Объект
$user = $stmt->fetch(
PDO::FETCH_OBJ
);Результат:
$user->name;Подготовленные запросы
Главное преимущество PDO.
Вместо:
$sql = "
SELECT *
FROM users
WHERE id = $id
";Используем:
$stmt = $pdo->prepare(
'SELECT * FROM users WHERE id = ?'
);
$stmt->execute([$id]);Теперь значение передаётся отдельно от SQL.
Именованные параметры
Более читаемый вариант:
$stmt = $pdo->prepare(
'
SELECT *
FROM users
WHERE email = :email
'
);
$stmt->execute([
'email' => $email
]);Плюсы:
- безопаснее
- легче читать
- меньше ошибок
INSERT
Добавление записи:
INSERT INTO users(name)
VALUES ('Alex');Через PDO:
$stmt = $pdo->prepare(
'
INSERT INTO users(name)
VALUES (:name)
'
);
$stmt->execute([
'name' => 'Alex'
]);Получение ID новой записи
После вставки:
$id = $pdo->lastInsertId();UPDATE
Изменение данных:
$stmt = $pdo->prepare(
'
UPDATE users
SET name = :name
WHERE id = :id
'
);
$stmt->execute([
'name' => 'John',
'id' => 1
]);DELETE
Удаление:
$stmt = $pdo->prepare(
'
DELETE FROM users
WHERE id = :id
'
);
$stmt->execute([
'id' => 1
]);Транзакции
Транзакция позволяет выполнить несколько операций как одно действие.
Перевод денег:
Списать деньги
+
Добавить деньгиЕсли одна операция упала:
Откатить всёНачало:
$pdo->beginTransaction();Подтверждение:
$pdo->commit();Откат:
$pdo->rollBack();Пример:
try {
$pdo->beginTransaction();
// SQL 1
// SQL 2
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
}Обработка ошибок
Через исключения:
try {
$pdo->query(
'INVALID SQL'
);
} catch (PDOException $e) {
echo 'Database error';
}В продакшене нельзя:
echo $e->getMessage();Потому что пользователь может увидеть:
Table users doesn't existЛучше:
log_error($e);
echo 'Something went wrong';Организация работы с БД
В небольших проектах:
src/
├─ database/
│ └─ connection.php
│
├─ models/
│ └─ User.php
│
└─ services/
Пример отдельного подключения:
function getConnection(): PDO
{
return new PDO(
'mysql:host=localhost;dbname=test',
'root',
'password'
);
}Подготовленные запросы vs ORM
PDO:
$stmt = $pdo->prepare(
'SELECT * FROM users'
);ORM:
User::all();PDO:
✅ полный контроль
✅ быстрее понять SQL
✅ меньше магии
ORM:
✅ меньше повторяющегося кода
✅ удобнее в больших проектах
Частые ошибки
Склеивать SQL строки
Плохо:
$sql =
"SELECT * FROM users WHERE id="
. $id;Проблема:
- SQL-инъекции
Не использовать prepare
Плохо:
$query(
"DELETE FROM users WHERE id=$id"
);Хранить пароль как обычный текст
Плохо:
$password = $_POST['password'];Лучше:
password_hash(
$password,
PASSWORD_DEFAULT
);Создавать новое подключение в каждом запросе
Плохо:
new PDO(...);
new PDO(...);
new PDO(...);Лучше:
- одно подключение
- передача зависимости
🎯 Вывод
- PDO – стандартный способ работы PHP с базами данных
- он поддерживает разные СУБД через драйверы
- всегда нужно использовать подготовленные запросы
prepare()защищает от SQL-инъекцийexecute()передаёт параметры отдельно от SQLfetch()получает одну записьfetchAll()получает список- транзакции нужны для связанных операций
- ошибки БД нужно обрабатывать через исключения
- PDO – основа перед использованием ORM