Привет, Хабр! Очень много статей написано о PDO, но при этом очень мало реальных примеров. В этой статье я хочу представить свою версию класса для работы с базой данных (далее — БД). Эта статья будет полезна начинающим программистам, которые только осваивают эту технологию.
Внимание! Моё мнение может отличаться от вашего, поэтому хочу сразу сказать, что эта статья не есть истина в последней инстанции и реализация этого класса зависит от программиста и его предпочтений.
Вступление
Начнём с класса DB.
<?php // use PDO - нужно только в том случае, если вы // Используете namespace выше. Далее по коду он будет // Но если он вам не нужен - спокойно удаляйте use PDO; class DB { public function __construct() { } } ?>
Тут, я думаю, всё понятно, эти вещи можно не объяснять.
Далее большая часть пояснений будет содержаться в коде.
<?php use PDO; class DB { // Переменная, хранящая объект PDO private $db; public function __construct() { // Файл dbinfo.php возвращает массив для // Подключения к БД $dbinfo = require 'path/to/dbinfo.php'; // Подключение $this->db = new PDO('mysql:host=' . $dbinfo['host'] . ';dbname=' . $dbinfo['dbname'], $dbinfo['login'], $dbinfo['password']); } } ?>
Прекрасно, мы подключились к БД. Теперь нам нужно создать метод, который позволит совершать SQL запросы.
<?php use PDO; class DB { // Объект класса PDO private $db; // Соединение с БД public function __construct() { $dbinfo = require 'path/to/dbinfo.php'; $this->db = new PDO('mysql:host=' . $dbinfo['host'] . ';dbname=' . $dbinfo['dbname'], $dbinfo['login'], $dbinfo['password']); } // Операции над БД public function query($sql, $params = []) { } } ?>
Реализация метода query
Мы готовы к реализации этого метода, но у нас возникает вопрос:
«Что за параметры он принимает и как он должен их использовать?»
Ответ на первый вопрос очевиден:
-
$sql— переменная с текстом SQL запроса. -
$params— переменная с какими-то параметрами для запроса.
А что со вторым вопросом?
Всё так же просто, что бы ответить на этот вопрос, мы должны узнать, в каком виде нам подают эти параметры. А получаем мы их вот такими:
<?php $sql = "SELECT * FROM `table` WHERE id = :id"; $params = [ 'id' => 5 ]; ?>
У незнающего человека возникает вопрос: «Что за двоеточие?» Я тут же отвечаю — такие запросы называются подготовленными и используются, дабы исключить возможность SQL инъекции.
Вернёмся к предыдущему вопросу и ответим на него:
Мы должны обойти массив $params и подставить значение в запрос.
Но сначала, мы должны подготовить запрос для подстановки этих значений. В итоге код будет выглядеть так:
<?php use PDO; class DB { // Объект класса PDO private $db; // Соединение с БД public function __construct() { $dbinfo = require 'path/to/dbinfo.php'; $this->db = new PDO('mysql:host=' . $dbinfo['host'] . ';dbname=' . $dbinfo['dbname'], $dbinfo['login'], $dbinfo['password']); } // Операции над БД public function query($sql, $params = []) { // Подготовка запроса $stmt = $this->db->prepare($sql); // Обход массива с параметрами // и подставление значений if ( !empty($params) ) { foreach ($params as $key => $value) { $stmt->bindValue(":$key", $value); } } // Выполняем запрос $stmt->execute(); // Возвращаем ответ return $stmt->fetchAll(PDO::FETCH_ASSOC); } } ?>
Некоторые комментарии немного искажают истину, но при этом кардинально ничего не меняют
Мы имеем уже довольно мощный инструмент, использующий подготовленные запросы и требующий от разработчиков знание SQL, а не тонкостей класса. Но при этом, я бы зашил в этот класс типовые запросы, такие как:
-
getAll()— двумерный массив, индексированный числами по порядку -
getRow()— одномерный массив, первую строку результата
Моя реализация
Эти методы могут быть реализованы по разному, но я представлю свою реализацию.
<?php use PDO; class DB { // Объект класса PDO private $db; // Соединение с БД public function __construct() { $dbinfo = require 'path/to/dbinfo.php'; $this->db = new PDO('mysql:host=' . $dbinfo['host'] . ';dbname=' . $dbinfo['dbname'], $dbinfo['login'], $dbinfo['password']); } // Операции над БД public function query($sql, $params = []) { // Подготовка запроса $stmt = $this->db->prepare($sql); // Обход массива с параметрами // и подставляем значения if ( !empty($params) ) { foreach ($params as $key => $value) { $stmt->bindValue(":$key", $value); } } // Выполняя запрос $stmt->execute(); // Возвращаем ответ return $stmt->fetchAll(PDO::FETCH_ASSOC); } public function getAll($table, $sql = '', $params = []) { return $this->query("SELECT * FROM $table" . $sql, $params); } public function getRow($table, $sql = '', $params = []) { $result = $this->query("SELECT * FROM $table" . $sql, $params); return $result[0]; } } ?>
Здесь эти методы реализованы, возможно не лучшим образом, но реализованы.
Так же сюда можно добавить ещё функции, упрощающие жизнь, но лично мне этого с головой хватает.
Можно добавить следующие методы:
-
getOne()— возвращает первый элемент первой строки результата -
getCol()— возвращает 1 колонку таблицы -
и т.д.
Применение
Мы написали наш класс. Теперь нам нужно протестировать его в реальном «бою».
Давайте попробуем. Для начала нам нужно создать любую таблицу в БД, допустим это будет таблица posts. Добавим туда пару записей и попробуем вывести их с помощью нашего класса.
Далее я не буду приводить код класса
DB. Подразумевается, что этот класс либо написан выше, либо подключается к этому скрипту.
Так как ранее я не показал файл dbinfo.php — сейчас я приведу код этого конфигурационного файла.
<?php // Не забудьте поменять данные return [ 'host' => '127.0.0.1', 'dbname' => 'test', 'login' => 'root', 'password' => '' ]; ?>
Это понятно и не требует объяснения, идём дальше. Теперь, давайте попросим БД test вернуть нам значение всех постов при помощи нашего класса.
<?php // class DB {...} // Создаём объект $db = new DB; // Получаем и выводим данные echo "<pre>"; print_r($db->getAll('posts')); ?>
На выходе мы имеем следующее:
Отлично, а теперь давайте выведем только первый пост.
<?php // class DB {...} // Создаём объект $db = new DB; // Получаем и выводим данные echo "<pre>"; print_r($db->getRow('posts')); ?>
Прекрасно. Ну и в конце добавим запись и выведем данные до и после.
<?php // class DB {...} // Создаём объект $db = new DB; // Получаем и выводим данные echo "<h1>До</h1><pre>"; print_r($db->getAll('posts')); echo "</pre><h1>После</h1><pre>"; $params = [ 'title' => 'Заголовок через PHP', 'author' => 'Автор через PHP' ]; $db->query('INSERT INTO `posts` ( title, author ) VALUES ( :title, :author )', $params); print_r($db->getAll('posts')); ?>
Результат:
Мы получили то, что хотели и убедились в том, что этот класс рабочий.
В заключении
В конце статьи я хочу повториться и сказать, что моя реализация не идеальна, но всё таки данный класс работает и выполняет свою главную функцию — работает с базой данных. Надеюсь для вас эта статья была полезной
Ссылка на github: class DB
ссылка на оригинал статьи https://habr.com/ru/post/535512/
Добавить комментарий