PHP PDO — работаем с базами данных правильно
Термин PDO является сокращением понятия PHP Data Objects. Как можно судить по названию, эта технология позволяет работать с содержимым базы данных через объекты.
Почему не myqli или mysql?
Чаще всего, в отношении новых технологий, встает вопрос их преимуществ перед старыми-добрыми и проверенными инструментами, а также, перевода на них текущих и старых проектов.
Объектная ориентированность PDOPHP развивается очень активно и стремится стать одним из лучших инструментов для быстрой разработки веб приложений как массового, так и корпоративного уровня.
Говоря о PHP, будем подразумевать современный объектно-ориентированный PHP, позволяющий писать универсальный код, удобный для тестирования и повторного использования.
Использование PDO позволяет вынести работу с базой данных на объектно-ориентированный уровень и улучшить переносимость кода. На самом деле, использование PDO не так сложно, как можно было бы подумать.
АбстракцияПредставим, что мы уже продолжительное время разрабатываем приложение, с использованием MySQL. И вот, в один прекрасный момент, появляется необходимость заменить MySQL на PostgreSQL.
Как минимум, нам придется заменить все вызовы mysqli_connect() (mysql_connect()) на pg_connect() и, по аналогии, другие функции, используемые для запроса и обработки данных.
При использовании PDO, мы ограничимся изменением нескольких параметров в файлах конфигурации.
Связывание параметровИспользование связанных параметров предоставляет большую гибкость в составлении запросов и позволяет улучшить защиту от SQL инъекций.
Получение данных в виде объектовТе, кто уже использует ORM (object-relational mapping — объектно-реляционное отображение данных), например, Doctrine, знают удобство представления данных из таблиц БД в виде объектов. PDO позволяет получать данные в виде объектов и без использования ORM.
Расширение mysql больше не поддерживаетсяПоддержка расширения mysql окончательно удалена из нового PHP 7. Если вы планируете переносить проект на новую версию PHP, уже сейчас следует использовать в нем, как минимум, mysqli. Конечно же, лучше начинать использовать PDO, если вы еще не сделали этого.
Мне кажется, что этих причин достаточно для склонения весов в сторону использования PDO. Тем более, не нужно ничего дополнительно устанавливать.
Проверяем наличие PDO в системе
Версии PHP 5.5 и выше, чаще всего, уже содержать расширение для работы с PDO. Для проверки достаточно выполнить в консоли простую команду:
Либо найти информацию в выводе встроенной PHP функции phpinfo() . Создадим для этого простой скрипт:
Теперь откроем его в любом браузере и найдем нужные данные поиском по строке PDO.
Знакомимся с PDO
Процесс работы с PDO не слишком отличается от традиционного. В общем случае, процесс использования PDO выглядит так:
- Подключение к базе данных;
- По необходимости, подготовка запроса и связывание параметров;
- Выполнение запроса.
Для подключения к базе данных нужно создать новый объект PDO и передать ему имя источника данных, так же известного как DSN.
В общем случае, DSN состоит из имени драйвера, отделенного двоеточием от строки подключения, специфичной для каждого драйвера PDO.
Для MySQL, подключение выполняется так:
В данном случае, DSN содержит имя драйвера mysql, указание хоста (возможен формат host=ИМЯ_ХОСТА:ПОРТ), имя базы данных, кодировка, имя пользователя MySQL и его пароль.
ЗапросыВ отличие от mysqli_query(), в PDO есть два типа запросов:
- Возвращающие результат (select, show);
- Не возвращающие результат (insert, detele и другие).
Первым делом, рассмотрим второй вариант.
Выполнение запросовРассмотрим пример выполнения запроса на примере insert.
Конечно же, данный запрос возвращает количество затронутых строк и увидеть его можно следующим образом.
Получение результатов запросаВ случае использования mysqli_query() , код мог бы быть следующим.
Для PDO, код будет проще и лаконичнее.
Режимы получения данныхКак и в mysqli, PDO позволяет получать данные в разных режимах. Для определения режима, класс PDO содержит соответствующие константы.
- PDO::FETCH_ASSOC — возвращает массив, индексированный по имени столбца в таблице базы данных;
- PDO::FETCH_NUM — возвращает массив, индексированный по номеру столбца;
- PDO::FETCH_OBJ — возвращает анонимный объект с именами свойств, соответствующими именам столбцов. Например, $row->id будет содержать значение из столбца id.
- PDO::FETCH_CLASS — возвращает новый экземпляр класса, со значениями свойств, соответствующими данным из строки таблицы. В случае, если указан параметр PDO::FETCH_CLASSTYPE (например PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE ), имя класса будет определено из значения первого столбца.
Примечание: это не полный список, все возможные константы и варианты их комбинации доступны в документации.
Пример получения ассоциативного массива:
Примечание: Рекомендуется всегда указывать режим выборки, так как режим PDO::FETCH_BOTH потребует вдвое больше памяти — фактически, будут созданы два массива, ассоциативный и обычный.
Рассмотрим использование режима выборки PDO::FETCH_CLASS . Создадим класс User :
Теперь выберем данные и отобразим данные при помощи методов класса:
Подготовленные запросы и связывание параметров
Для понимания сути и всех преимуществ связывания параметров нужно более подробно рассмотреть механизмы PDO. При вызове $statement->query() в коде выше, PDO подготовит запрос, выполнит его и вернет результат.
При вызове $connection->prepare() создается подготовленный запрос. Подготовленные запросы — это способность системы управления базами данных получить шаблон запроса, скомпилировать его и выполнить после получения значений переменных, использованных в шаблоне. Похожим образом работают шаблонизаторы Smarty и Twig.
При вызове $statement->execute() передаются значения для подстановки в шаблон запроса и СУБД выполняет запрос. Это действие аналогично вызову функции шаблонизатора render() .
Пример использования подготовленных запросов в PHP PDO:
В коде выше подготовлен запрос выборки записи с полем id равным значению, которое будет подставлено вместо :id . На данном этапе СУБД выполнит анализ и компиляцию запроса, возможно с использованием кеширования (зависит от настроек).
Теперь нужно передать недостающий параметр и выполнить запрос:
И получить данные:
Преимущества использования связанных параметровВозможно, после рассмотрения механизма работы подготовленных запросов и связанных параметров, преимущества их использования стали очевидными.
PDO предоставляет удобную возможность экранирования пользовательских данных, например, такой код больше не нужен:
Вместо этого, теперь целесообразно делать так:
Можно, даже, еще укоротить код, используя нумерованные параметры вместо именованных:
В тоже время, использование подготовленных запросов позволяет улучшить производительность при многократном использовании запроса по одному шаблону. Пример выборки пяти случайных пользователей из базы данных:
При вызове метода prepare() , СУБД проведет анализ и скомпилирует запрос, при необходимости использует кеширование. Позже, в цикле for , происходит только выборка данных с указанным параметром. Такой подход позволяет быстрее получить данные, уменьшив время работы приложения.
При получении общего количества пользователей в базе данных был использован метод fetchColumn() . Этот метод позволяет получить значение одного столбца и является полезным при получении скалярных значений, таких как количество, сумма, максимально или минимальное значения.
Связанные значения и оператор INЧасто, при начале работы с PDO, возникают трудности с оператором IN . Например, представим, что пользователь вводит несколько имен, разделенных запятыми. Пользовательский ввод хранится в переменной $names :
НЕ корректный код:
Этот код не будет работать потому, что параметр в шаблоне представлен скалярным значением (например, целое число или строка).
Правильным подходом будет создание специальной строки:
Как видно из код, в строке 2 создаем массив размером как $names и заполняем его символами ? , а затем, формируем из него строку, содержащую элементы массива, разделенные запятыми. В результате получается строка наподобие . . При передаче массива $names в методе execute() , первый элемент массива будет сопоставлен первому знаку вопроса, второй второму и так далее.
Типизированные связанные параметрыРассмотренные выше примеры были намеренно упрощены и не содержали указания типов параметров. Однако, в реальном коде лучше использовать указание типов.
- Читабельность. Для читающих код проще будет его понять;
- Обслуживаемость. Знание типов передаваемых параметров упрощает отладку кода. Например, при передаче строкового значения в параметр, который ожидает целое число, вызовет соответствующую ошибку;
- Ускорение. Явное указание типа параметра избавляет СУБД от необходимости приведения типов.
Для явного указания типов параметров лучше использовать метод bindValue() . Например,
В коде выше параметр определен в вызове метода bindValue() , а метод execute() вызывается без параметров.
Примечание: В примере выше, первым параметром метода bindValue() , является 1 . При использовании именованных параметров, первым параметром передается соответствующее имя переменной в шаблоне. В противном случае. первым параметром передается порядковый номер переменной в шаблоне. Обратите внимание, что нумерация начинается с 1, а не с 0!
Заключение
PHP развивается, программисты не должны отставать. Использование расширения PDO позволяет писать более краткий, лаконичный, быстрый и безопасный код. Почему бы не начать использовать его уже сейчас?
6 thoughts on “ PHP PDO — работаем с базами данных правильно ”
Спасибо большое, все понятно и ничего лишнего.
Очень хорошая статья, мне очень сильно помог. Спасибо за статью
А мне не помогло. Мне вообще ничего не помогает уже
Добрый день, подскажите пожалуйста, в строке $affectedRows = $connection->exec(‘INSERT INTO users VALUES (1, «somevalue»‘); как должны быть расставлены апострофы?
$statement = $connection->query(‘SELECT * FROM users’);
while($row = $statement->fetch(PDO::FETCH_CLASS))
2015 — программисты не должны отставать 2016 — 2017 — 2018 — 2019 :-)