Включите исполнение JavaScript в браузере, чтобы запустить приложение.
27 мая 2025

Как работать с базами данных в PHP с помощью модуля PDO

В PHP для работы с базами данных часто используется расширение PDO. В статье рассмотрим, что это, каковы его преимущества и особенности, как подключиться к базе данных через него, а также приведем примеры запросов.

Что такое 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);
php
  • Несколько режимов обработки ошибок. 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();
?>
php
  • Несколько методов выборки данных, приведем часть из них. 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';
php

Далее создадим таблицу с книгами и заполним ее значениями:

-- Выбор базы данных
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');
php

Затем сформируем строку 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);
php

Примеры выполнения 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";
}
?>
php

Результат — ассоциативный массив:

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
php

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";
}
?>
php

Результат — нумерованный массив:

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
php

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";
}
?>
php

Результат:

ID: 1, Title: The captain's daughter
ID: 2, Title: The Master and Margarita
ID: 3, Title: The Government Inspector
php

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"; 
}
?>
php

Результат:

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
php

PDO::FETCH_COLUMN возвращает значения выбранного столбца в виде одномерного массива:

<?php
$stmt = $pdo->query("SELECT title FROM books"); 


while ($title = $stmt->fetch(PDO::FETCH_COLUMN)) { 
    echo "Title: " . $title . "\n";
}
?>
php

Результат:

Title: The captain's daughter
Title: The Master and Margarita
Title: The Government Inspector
php

Прямые и подготовленные запросы

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'
]);
php