Что такое PDO в PHP
PDO — это универсальный интерфейс для работы с популярными системами управления базами данных в PHP. Доступ к MySQL, PostgreSQL, SQLite, Microsoft SQL Server и другим осуществляется через единый API.
К преимуществам расширения можно отнести:
- поддержку многих распространенных СУБД;
- универсальность — с разными системами управления базами данных можно взаимодействовать одинаковым образом;
- встроенные подготовленные запросы для защиты от SQL-инъекций;
- отсутствие необходимости установки дополнительных библиотек: PDO — это компонент стандартного пакета PHP.
Почему стоит использовать PDO для работы с базами данных
Рассмотрим плюсы расширения более подробно:
- Универсальность. Уже отмечалось, что PDO позволяет работать со многими популярными СУБД, при этом программист может написать код один раз и использовать его для нескольких баз данных. Единственный нюанс — для разных СУБД нужно менять строку DSN (Data Source Name) — данные для подключения к базе данных, представленные в виде строки, например:
<?php
// MySQL
$dsn_mysql = 'mysql:host=127.0.0.1;dbname=library;charset=utf8mb4';
$pdo_mysql = new PDO($dsn_mysql, 'user', 'password');
// PostgreSQL
$dsn_pgsql = 'pgsql:host=127.0.0.1;port=5432;dbname=library';
$pdo_pgsql = new PDO($dsn_pgsql, 'user', 'password');
// SQLite
$dsn_sqlite = 'sqlite:/path/to/database/library.db';
$pdo_sqlite = new PDO($dsn_sqlite);
- Несколько режимов обработки ошибок. PDO::ERRMODE_SILENT — режим по умолчанию, информация об ошибке просто записывается (получить ее можно с помощью методов errorInfo() и errorCode()), выполнение скрипта не прерывается. PDO::ERRMODE_WARNING — информация об ошибке также записывается, выполнение не прерывается, но генерируется предупреждение. PDO::ERRMODE_EXCEPTION — рекомендуемый режим, при котором PDO выбрасывает исключение, при этом выполнение скрипта прерывается.
Удобное выполнение транзакций (нескольких SQL-запросов, выполняемых пакетом в случае, если ни один из них не завершается ошибкой):
<?php
try {
// Начало транзакции — запросы после вызова beginTransaction() не применятся, пока не будет вызван метод commit()
$pdo->beginTransaction();
// Добавление новой книги
$pdo->exec("INSERT INTO books (title, author, genre) VALUES ('New Book', 'Author', 'Fiction')");
// Обновление количества книг
$pdo->exec("UPDATE authors SET book_count = book_count + 1 WHERE name = 'Author'");
// Метод commit() для фиксации изменений
$pdo->commit();
echo "Транзакция выполнена успешно!";
} catch (PDOException $e) {
// rollBack() вызывает отказ транзакции
$pdo->rollBack();
echo "Ошибка: " . $e->getMessage();
?>
- Несколько методов выборки данных, приведем часть из них. PDO::FETCH_ASSOC — возвращает ассоциативный массив, где ключ — имя столбца. PDO::FETCH_NUM — строки возвращаются как нумерованный массив, где индексы представляют номера столбцов. PDO::FETCH_BOTH — метод по умолчанию, строки возвращаются как ассоциативный и нумерованный массив одновременно. PDO::FETCH_OBJECT — строки возвращаются как анонимные объекты, где свойствами становятся имена столбцов, а результат записывается в значение свойств.
Подключение к базе данных MySQL через PDO
Вначале создадим базу данных:
CREATE DATABASE library CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- Создание пользователя и предоставление прав доступа к базе данных
GRANT ALL PRIVILEGES ON library.* TO 'libuser'@'localhost'
IDENTIFIED BY 'libpassword';
Далее создадим таблицу с книгами и заполним ее значениями:
-- Выбор базы данных
USE library;
-- Создание таблицы
CREATE TABLE books (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
title VARCHAR(255) NOT NULL,
author VARCHAR(255) NOT NULL,
genre VARCHAR(50) NOT NULL
);
-- Заполнение таблицы
INSERT INTO books(title, author, genre)
VALUES
('The captain's daughter', 'A. Pushkin', 'Novel'),
('The Master and Margarita', 'M. Bulgakov', 'Novel'),
('The Government Inspector', 'N. Gogol', 'Comedy');
Затем сформируем строку DSN и подключимся к MySQL через PDO:
<?php
// Настройки подключения
// Дополнительно нужно указать порт, если используется не 3306
$host = '127.0.0.1'; // Имя хоста
$db = 'library'; // Имя базы данных
$user = 'libuser'; // Имя пользователя
$pass = 'libpassword'; // Пароль
$charset = 'utf8mb4'; // Кодировка (опционально)
// Формирование строки DSN (Data Source Name) — в начале указывается префикс базы данных, отделяемый двоеточием. Далее параметры разделяются точкой с запятой
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
try {
// Создание объекта PDO для подключения — указывается строка DSN, имя пользователя и пароль
$pdo = new PDO($dsn, $user, $pass);
// Метод setAttribute() позволяет указать дополнительные параметры
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Подключение к базе данных выполнено успешно!";
} catch (PDOException $e) {
echo "Ошибка подключения: " . $e->getMessage();
}
?>
// Альтернативно параметры могут быть указаны в массиве
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];
// Тогда его надо добавить в строку DSN
$pdo = new PDO($dsn, $user, $pass, $options);
Примеры выполнения SQL-запросов с использованием PDO
Рассмотрим примеры с разными методами выборки:
- PDO::FETCH_ASSOC:
<?php
$stmt = $pdo->query("SELECT * FROM books");
$books = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Форматирование вывода
foreach ($books as $book) {
echo "Title: " . $book['title'] . ", Author: " . $book['author'] . ", Genre: " . $book['genre'] . "\n";
}
?>
Результат — ассоциативный массив:
Title: The captain's daughter, Author: A. Pushkin, Genre: Novel
Title: The Master and Margarita, Author: M. Bulgakov, Genre: Novel
Title: The Government Inspector, Author: N. Gogol, Genre: Comedy
PDO::FETCH_NUM:
<?php
$stmt = $pdo->query("SELECT * FROM books");
$books = $stmt->fetchAll(PDO::FETCH_NUM);
foreach ($books as $book) {
echo "ID: " . $book[0] . ", Title: " . $book[1] . ", Author: " . $book[2] . ", Genre: " . $book[3] . "\n";
}
?>
Результат — нумерованный массив:
ID: 1, Title: The captain's daughter, Author: A. Pushkin, Genre: Novel
ID: 2, Title: The Master and Margarita, Author: M. Bulgakov, Genre: Novel
ID: 3, Title: The Government Inspector, Author: N. Gogol, Genre: Comedy
PDO::FETCH_KEY_PAIR возвращает ассоциативный массив, где ключи — данные из первого столбца выборки, а значения — из второго:
<?php
$stmt = $pdo->query("SELECT id, title FROM books");
$books = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
foreach ($books as $id => $title) {
echo "ID: $id, Title: $title\n";
}
?>
Результат:
ID: 1, Title: The captain's daughter
ID: 2, Title: The Master and Margarita
ID: 3, Title: The Government Inspector
PDO::FETCH_CLASS возвращает анонимный объект для каждой строки, где свойства — имена столбцов, а результат запроса — их значения, но требует указания класса, который нужно использовать для создания объекта:
<?php
class Book {
public $id;
public $title;
public $author;
public $genre;
// Метод для вывода описания
public function getDescription() {
return "{$this->title} by {$this->author}, Genre: {$this->genre}";
}
}
$stmt = $pdo->query("SELECT * FROM books");
$stmt->setFetchMode(PDO::FETCH_CLASS, 'Book');
while ($book = $stmt->fetch()) {
echo $book->getDescription() . "\n";
}
?>
Результат:
The captain's daughter by A. Pushkin, Genre: Novel
The Master and Margarita by M. Bulgakov, Genre: Novel
The Government Inspector by N. Gogol, Genre: Comedy
PDO::FETCH_COLUMN возвращает значения выбранного столбца в виде одномерного массива:
<?php
$stmt = $pdo->query("SELECT title FROM books");
while ($title = $stmt->fetch(PDO::FETCH_COLUMN)) {
echo "Title: " . $title . "\n";
}
?>
Результат:
Title: The captain's daughter
Title: The Master and Margarita
Title: The Government Inspector
Прямые и подготовленные запросы
PDO предлагает два способа выполнения SQL-запросов: прямые и подготовленные. Прямые используются, когда запрос безопасен и не содержит переменных, а для их создания предусмотрено два метода:
- query() для операторов SELECT, SHOW, DESCRIBE и т. д. Возвращает объект PDOStatement, из которого можно извлечь результаты запроса методами fetch() или fetchAll();
- exec() для запросов, которые не возвращают данные (операторы INSERT, UPDATE, DELETE, CREATE, DROP и т. д.). Возвращает число обработанных строк.
Подготовленные запросы позволяют защитить систему от SQL-инъекций — их рекомендуется использовать всегда. Допустим, в таблицу с книгами нужно вставить новую строку:
<?php
// Метод prepare() подготавливает запрос и принимает псевдопеременные, в данном случае неименованные, обозначаемые знаками вопросов
$stmt = $pdo->prepare("INSERT INTO books (title, author, genre) VALUES (?, ?, ?)");
// Метод execute() принимает значения для замены псевдопеременных в том же порядке, как они указывались в prepare() и выполняет запрос
$stmt->execute(['The Storm', 'A. Ostrovsky', 'Play']);
echo "New book added!";
?>
// prepare() с именованными псевдопеременными может выглядеть так
$stmt = $pdo->prepare("INSERT INTO books (title, author, genre) VALUES (:title, :author, :genre)");
// Тогда в execute() не обязательно передавать значения в том же порядке
$stmt->execute([
':author' => 'A. Ostrovsky',
':title' => 'The Storm',
':genre' => 'Play'
]);