Пожалуй одно из главных предназначений PHP, это взаимодействие с базой данных (чтение, запись, редактирование и удаление данных) на веб-сервере. Именно это позволяет веб-мастерам поддерживать и развивать динамические сайты с тысячами страниц.
Что такое реляционная база данных
Реляционная база данных – это база данных основанная на реляционной модели (от англ. relationship — отношение, связь) выражаясь по другому, это некий набор данных с определёнными связями между ними. Обычно такие базы организованны в виде таблиц. В отдельных таблицах хранится сгруппированная по определённому смыслу информация о какой-либо сущности, например данные о покупателях (сущность — покупатель) или данные о товарах (сущность — товар) и т.д. Каждый столбец таблицы отвечает за хранение одного свойства сущности, внутри ячейки хранится значение свойства сущности, например столбец — цена, значение — 1000.
Преимущественно отдельные столбцы имеют строго определённый тип данных (числовой, логический, текстовый, дату и время и т.д.). Каждая стока таблицы это набор значений свойств относящихся к определённой сущности (напр. определённому пользователю может соответствовать строка где хранит его имя, фамилия, телефон, email, возраст и пол.). Каждая строка в таблице должна иметь уникальный идентификатор, а так же так называемый «первичный ключ» (часто первичный ключ = уникальный идентификатор). При помощи первичного ключа, несколько таблиц базы данных могут быть связаны, например в таблице users — хранятся пользователи, а в таблице orders — заказы пользователей сделанные в интернет-магазине. По первичному ключу user_id (идентификатор пользователя) мы можем узнать что этот пользователь заказал, т.е. получить данные из таблицы orders.
Для работы с реляционными базами данных существует множество инструментов, они позволяют «вытаскивать» из БД различные наборы данных, даже более сложные чем в приведённом примере, при этом, структура таблиц не требует реорганизации.
СУБД MySQL
Что же такое MySQL? Это надежная. быстрая и универсальная система управления базами данных (СУБД), пожалуй самая популярная в мире (в 2019 году 39% разработчиков использовали MySQL в своих проектах). Несмотря на более слабый функционал в сравнении с PostgreSQL, данная СУБД прекрасно масштабируется и отлично подходит для большинства проектов.
MySQL — идеальный выбор для разработке веб-приложений. Данная СУБД входит в стандартный набор: Linux, Apache HTTP Server, MySQL и PHP (LAMP — набор программ с открытым исходным кодом). Так же не основе MySQL работает большинство популярных CMS ( Content Management System — система управление содержимым), таких как WordPress, OpenCart, 1С Битрикс и т.д.
К преимуществам этой СУБД можно отнести:
- Простота: Mysql легко установить на любую платформу (Linux, Windows, MacOS), под эту СУБД написано множество настольных приложений позволяющих работать с базой в визуальном режиме (очень удобно особенно для новичков), к подобным системам относятся Workbench, Navicat, PHPMyAdmin и другие.
- Много функций: MySQL поддерживает весь функционал реализованный на языке SQL.
- Безопасность: в СУБД MySQL встроено много функций безопасности, например Access Control Lists и поддержка SSH-зашифрованных соединений.
- Масштабируемость: MySQL достаточно легко и не дорого масштабируется, что позволяет разрабатывать на ней довольно крупные и высоко-нагруженные проекты.
В большинстве языков программирования встроена поддержка СУБД MySQL, PHP так же не стал исключением.
PHP PDO
PDO — это специализированный класс реализующий интерфейс доступа к базе данных. Его отличает универсальность, т.к. вам без разницы какая база данных будет использована.
Подключение к БД
Для подключения к БД необходимо создать экземпляр класса PDO и передать в него параметры подключения:
/* Подключение к базе данных MySQL с помощью PDO */
$dsn = 'mysql:dbname=testdb;host=localhost';
$user = 'root';
$password = '123456';
//Чтобы перехватить ошибки подключения используем исключения try {...} catch () {...}
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
//В случае ошибки выводим сообщения из перехваченного исключения
echo 'Подключение к БД не удалось: ' . $e->getMessage();
}
Конструктор PDO так же поддерживает и четвёртый параметр options — это массив ключ=>значение специфичных для драйвера (например MySQL или PostgreSQL) настроек подключения. Например сразу после подключения можно выполнить MySQL запрос указав это в параметре options:
//Чтобы перехватить ошибки подключения используем исключения try {...} catch () {...}
try {
$dbh = new PDO(
$dsn,
$user,
$password,
[PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"] //Команда которую необходимо выполнить сразу после подключения к серверу
);
} catch (PDOException $e) {
//В случае ошибки выводим сообщения из перехваченного исключения
echo 'Подключение к БД не удалось: ' . $e->getMessage();
}
Полный перечень параметров доступных в options вы найдёте в документации.
Базовый набор операций (CRUD)
Большинство веб-приложений работающих с базой данных, так или иначе реализуют базовый набор операций, а именно Create — создание, Read — чтение, Update — обновление и Delete — удаление (CRUD). Давайте рассмотрим как этот набор операций сделать в PDO.
Создание
Для теста, давайте создадим таблицу с пользователями сайта и заполним её данными. Таблица будет называться просто users и иметь 4 поля:
- id — автоинкрементный идентификатор записи
- name — имя пользователя
- email — адрес электронной почты
- phone — контактный телефон
try {
//Соединяемся с базой данных
$dbh = new PDO('mysql:dbname=test_db;host=localhost', $user, $password);
//запрос на создание таблицы
$sqlCreateTable = 'CREATE TABLE `users` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `email` VARCHAR(255) NOT NULL, `phone` VARCHAR(255) NOT NULL, PRIMARY KEY (`id`)) ';
$dbh->exec($sqlCreateTable);
echo 'Создана таблица <b>users</b>';
} catch(PDOException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
Здесь мы используем метод exec() он запускает запрос на выполнение возвращая количество затронутых строк. Метод не предназначен для выборки данных из таблицы. Если всё сделано верно у вас будет создана таблица пользователей. Давайте заполним её данными.
/*Данные пользователей, в реальном проектк они могут
быть получены из JSON, файла импорта или из формы регистрации */
$usersData = [
[
'name'=>'Иван Иванов',
'email'=>'ivan@mail.ru',
'phone'=>'+79001234567'],
[
'name'=>'Пётр Петров',
'email'=>'petrov@yandex.ru',
'phone'=>'+79281534874'],
[
'name'=>'Олег Сидоров',
'email'=>'sidor@gmail.com',
'phone'=>'+79508975248'
],
];
try {
//Соединяемся с базой данных
$dbh = new PDO('mysql:dbname=test_db;host=localhost', $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Подготовка запроса, обратите внимание что ключи в запросе совпадают с ключами массив отдельного пользователя
$data = $dbh->prepare('INSERT INTO users (name, email, phone) VALUES(:name, :email, :phone)');
//Перебираем массив пользователей
foreach ($usersData as $user) {
//Подставляем данные пользователей в запрос
$data->execute($user);
}
} catch(PDOException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
Если всё сделано верно, вы получите заполненную таблицу users:
Чтение
Прочитать записи в таблице БД можно несколькими способами, при помощи метода query и execute , давайте разберём оба:
Чтение таблицы при помощи метода query
$user = 'root';
$password = 'Ваш пароль';
//Чтобы перехватить ошибки подключения используем исключения try {...} catch () {...}
try {
$dbh = new PDO('mysql:dbname=test_db;host=localhost', $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Выборка всех записей
$users = $dbh->query('SELECT * FROM `users`');
echo '<ul>';
foreach ($users as $user){
echo '<li>id: ' . $user['id'] . ' - name: ' . $user['name'] . ' - phone: ' . $user['phone'] . ' - email: <a href="'. $user['email'] . '">'. $user['email'] .'</a></li>';
}
echo '</ul>';
} catch (PDOException $e) {
//В случае ошибки выводим сообщения из перехваченного исключения
echo 'Ошибка: ' . $e->getMessage();
}
В результате на экране вы увидите такую картину:Обратите внимание на следующее:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Данные параметры устанавливают расширенный режим вывода ошибок и исключение PDO.
Чтение таблицы при помощи метода execute
Давайте выберем из БД одного пользователя по конкретному email адресу.
try {
$dbh = new PDO('mysql:dbname=test_db;host=localhost', $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Вывод пользователя с email адресом ivan@mail.ru
//Подготовка запроса
$data = $dbh->prepare('SELECT * FROM `users` WHERE `email` = :user_email');
// Выполнение с подстановкой параметра в запрос
$data->execute(['user_email'=>'ivan@mail.ru']);
//Получаем результат
$users = $data->fetchAll();
echo '<ul>';
foreach ($users as $user){
echo '<li>id: ' . $user['id'] . ' - name: ' . $user['name'] . ' - phone: ' . $user['phone'] . ' - email: <a href="'. $user['email'] . '">'. $user['email'] .'</a></li>';
}
echo '</ul>';
} catch (PDOException $e) {
//В случае ошибки выводим сообщения из перехваченного исключения
echo 'Ошибка: ' . $e->getMessage();
}
В данном примере используется метод prepare т.е. подготовка запроса. Это позволят почти с 100% гарантией избежать SQL инъекций т.к. подставляемый параметры email не встраивается в зарос напрямую, в запросе есть лишь метка :email куда через метод execute будет подставлена переданная через ассоциативный массив переменная.
В результате выполнения запроса, получаем одну запись из таблицы users:
Редактирование
Давайте теперь изменим контактный телефон для пользователя с id равным 2 и сразу посмотрим на результат (выведем на экран список всех пользователей).
try {
//Соединяемся с базой данных
$dbh = new PDO('mysql:dbname=test_db;host=localhost', $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Подготовка запроса
$data = $dbh->prepare('UPDATE users SET phone = :phone WHERE id = :id');
//Подстановка параметров
$data->execute([
'phone'=>'+7 900 000 00 00',
'id' => 2
]);
//Выведем на экран сколько строк затронул наш запрос
echo 'Обновлено строк таблицы: ' . $data->rowCount();
//И сразу посмотрим на результат, выведем всех пользователей
$users = $dbh->query('SELECT * FROM `users`');
echo '<ul>';
foreach ($users as $user){
echo '<li>id: ' . $user['id'] . ' - name: ' . $user['name'] . ' - phone: ' . $user['phone'] . ' - email: <a href="'. $user['email'] . '">'. $user['email'] .'</a></li>';
}
echo '</ul>';
} catch(PDOException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
Как видите, запись обновилась:Отлично, осталось понять как удалять запись. Давайте удалим того же пользователя, этот Пётр Петров мне надоел =)
Удаление
И так, мы знаем что у пользователя Пётр Петров id равен 2, приступим:
try {
//id пользователя Пётр Петров
$id = 2;
//Соединяемся с базой данных
$dbh = new PDO('mysql:dbname=test_db;host=localhost', $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Подготовка запроса
$data = $dbh->prepare('DELETE FROM users WHERE id = :id');
$data->bindParam('id', $id);
$data->execute();
echo 'Удалено записей: ' . $data->rowCount();
} catch(PDOException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
Как видите, здесь для подстановки параметра в запрос мы использовали метод bindParam() им удобно пользоваться когда нам нужно подставить единичную переменную в запрос. Обратите внимание, что второй аргумент не может быть передан напрямую в виде значение (нельзя написать просто 2), мы должны передать именно переменную (которую по идеи нужно предварительно проверить и всё такое).
Как видите работать с PDO да и в целом с базами данных в PHP не так уж и сложно. Надеюсь статья была вам полезна. Желаю удачи!