Reg.ru: домены и хостинг
Крупнейший регистратор и хостинг-провайдер в России.
Более 2 миллионов доменных имен на обслуживании.
Продвижение, почта для домена, решения для бизнеса.
Более 700 тыс. клиентов по всему миру уже сделали свой выбор.
Бесплатный Курс "Практика HTML5 и CSS3"
Освойте бесплатно пошаговый видеокурс
по основам адаптивной верстки
на HTML5 и CSS3 с полного нуля.
Фреймворк Bootstrap: быстрая адаптивная вёрстка
Пошаговый видеокурс по основам адаптивной верстки в фреймворке Bootstrap.
Научитесь верстать просто, быстро и качественно, используя мощный и практичный инструмент.
Верстайте на заказ и получайте деньги.
*Наведите курсор мыши для приостановки прокрутки.
Основы работы с расширением PDO
Сегодня мы с вами разберём очень интересную тему - основы работы с расширением PDO для PHP.
PDO (PHP Data Objects) - это просто некий интерфейс, который позволяет работать с различными базами данных без учета их специфики. С помощью PDO мы можем легко переключаться между разными базами данных и управлять ими. Чтобы стало понятнее, давайте разберём пример.
Как мы должны были подключаться раньше к базе MySQL?
mysql_connect($host, $user, $password); mysql_select_db($db);
Чтобы подключиться к SQLite мы должны были написать так:
sqlite_open($db);
Если нам нужна база данных PostgreSQL, то надо написать так:
pg_connect("host=$host, dbname=$db, user=$user, password=$password");
Не очень-то удобно, верно? Получается, что если мы захотим сменить базу данных, то нам придется переделывать много кода. И вот, чтобы это исправить, появилось специальное PHP-расширение - PDO.
Давайте посмотрим, как мы теперь можем подключиться к базе:
MySQL:
$db = new PDO("mysql:host=$host;dbname=$db", $user, $password);
SQLite:
$db = new PDO("sqlite:$db);
PostgreSQL:
$db = new PDO("pgsql:host=$host;dbname=$db", $user, $password);
Как видите, всё то же самое, кроме строки подключения. Это единственное различие.
Теперь давайте рассмотрим, как раньше мы были должны выполнять запросы:
$sql = "INSERT INTO(name, email) VALUES($name, $email)"; // MySQL mysql_query($sql); // SQLite sqlite_query($sql); // PostgreSQL pg_query($sql);
Теперь же мы можем абстрагироваться от этого:
// PDO $result = $db->exec($sql);
Всё! Наш запрос будет выполнен независимо от того, какую БД мы используем, а в переменную result попадёт количество затронутых строк.
Однако выбрать что-то из базы данных таким способом мы не сможем. Для выборки нам нужно использовать не exec, а query.
$sql = "SELECT name FROM users"; $result = $db->query($sql);
Теперь давайте вспомним и о безопасности, ведь все данные нужно проверять. Как мы делали это раньше?
$sql = "SELECT * FROM users WHERE name = $name"; $name = $_POST["name"]; // MySQL $name = mysql_real_escape_string($name); // SQLite $name = sqlite_escape_string($name); // PostgreSQL $name = pg_escape_string($name);
Теперь же нам не нужно этого делать. PDO сделает всё за нас.
$name = $db->quote($name); $result = $db->query($sql);
PDO сам всё проверит и обработает переданные данные. Круто?:) Дальше ещё круче! Продолжим.
Как мы раньше преобразовывали результат в массив? Рассмотрим на примере базы MySQL.
$result = mysql_query($sql); // Так $row = mysql_fetch_assoc($result); // Или так... $row = mysql_fetch_array($result, FETCH_ASSOC);
Также, как и ассоциативный, мы могли получить и нумерованный массив. Теперь рассмотрим как это делается в PDO:
$stmt = $db->query($sql); // Ассоциативный $result = $stmt->FETCH(PDO::FETCH_ASSOC); // Нумерованный $result = $stmt->FETCH(PDO::FETCH_NUM); // Оба типа массивов одновременно $result = $stmt->FETCH(PDO::FETCH_BOTH); // Объект $result = $stmt->FETCH(PDO::FETCH_OBJ);
Использовать это также очень просто:
// Ассоциативный echo $result["name"]; // Нумерованный echo $result[0]; // Объект echo $result->name;
Для "ленивых" есть такая вещь:
$stmt = $db->query($sql); $result = $stmt->FETCH(PDO::FETCH_LAZY);
Он возвращает сразу все 3 типа. Т.е. это FETCH_BOTH и FETCH_OBJ вместе. Как вы уже догадались, после этого доступ к данным можно получить любым из трех способов:
echo $result->name; echo $result["name"]; echo $result[0];
Однако Fetch возвращает только одну запись, поэтому, если мы хотим получить все записи, то надо использовать FetchAll.
$stmt = $db->query("SELECT * FROM users"); $result = $stmt->FetchAll(PDO::FETCH_ASSOC); foreach($result as $user) { echo $user["name"]."<br>"; }
Но есть ещё одна классная штука, связанная с Fetch. С ее помощью мы можем заполнить наш класс данными из БД автоматически.
class User { public $login; public $id; public function showInfo() { echo "<b>".$this->id."</b>"." : ".$this->login."<br>"; } } $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $stmt = $db->query("SELECT * FROM `users`"); $result = $stmt->fetchAll(PDO::FETCH_CLASS, "User"); foreach($result as $user) { $user->showInfo(); }
Как видите всё очень просто. Нам нужно просто указать константу FETCH_CLASS и через запятую в кавычках название класса, куда будут вставлены данные.
Потом перебираем в цикле объект и выводим нужную нам информацию.
Внимание! Названия свойств в классе должны совпадать с названиями полей в базе данных.
Помимо всего прочего, мы можем создавать так называемые подготовленные запросы. В чём их плюсы?
1. Мы можем один раз подготовить запрос, после чего запускать его столько раз, сколько нам нужно. Причём как с такими же, так и с другими параметрами.
Когда запрос подготовлен, СУБД анализирует его, компилирует и оптимизирует план его выполнения. В случае сложных запросов, время на выполнение будет ощутимо, если мы запускаем его с разными параметрами. В случае с подготовленными запросами это делается один раз и, следовательно, времени тратится меньше.
2. Параметры подготовленного запроса не требуется экранировать кавычками, драйвер делает это автоматически. Если в приложении используются только подготовленные запросы, то SQL-иньекции почти невозможны.
PDO может эмулировать подготовленные запросы, если они не поддерживаются драйвером. Теперь, давайте рассмотрим, как же их использовать?
$stmt = $db->prepare("INSERT INTO users (name, login) VALUES (:name, :login)"); $stmt->bindParam(':name', $name); $stmt->bindParam(':login', $login); // Вставим одну строку с такими значениями $name = 'vasya'; $login = 'vasya123'; $stmt->execute(); // Теперь другую строку с другими значениями $name = 'petya'; $login = 'petya123'; $stmt->execute();
Метод bindParam позволяет нам установить параметры. Думаю, тут всё понятно. Сначала там, где хотим, чтобы были вставлены данные, пишем такую строчку ":имя". А затем указываем, откуда они будут браться. В данном случае они будут браться из переменных name и login.
Теперь мы можем использовать этот запрос с разными параметрами сколько угодно раз, а чтобы его выполнить, нужно вызвать метод execute. Это были именованные параметры. Также есть и не именованные.
$stmt = $db->prepare("INSERT INTO users (name, login) VALUES (?, ?)"); // Данные из переменной name будут вставлены вместо первого знака вопроса $stmt->bindParam(1, $name); // Данные из переменной login будут вставлены вместо второго знака вопроса $stmt->bindParam(2, $login); // Вставим одну строку с такими значениями $name = 'vasya'; $login = 'vasya123'; $stmt->execute(); // Теперь другую строку с другими значениями $name = 'petya'; $login = 'petya123'; $stmt->execute();
Следующий момент - как нам отлавливать ошибки?
Для этого есть класс PDOException. Я рекомендую все ваши запросы писать в блоке try-catch.
try { $db = new PDO("myql:host=localhost;dbname=test", "root", ""); $stmt = $db->query("SELECT * FROM users"); $result = $stmt->fetch(PDO::FETCH_ASSOC); echo $result["login"]; } catch(PDOException $e) { echo "Ошибка: ".$e->getMessage()."<br>"; echo "На линии: ".$e->getLine(); }
Здесь мы допустили ошибку и написали myql вместо mysql. И класс PDOException нам об этом напишет.
У него несколько методов, но самые часто используемые это getMessage(), который возвращает нам текст ошибки и getLine(), который возвращает номер строки, на которой допущена ошибка.
Ну и напоследок поговорим о транзакциях. Сначала приведу код.
try { $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $db->beginTransaction(); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES('login1')"); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES('login2')"); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES('login3')"); $db->commit(); } catch(PDOException $e) { $db->rollBack(); }
Здесь мы начинаем транзакцию с помощью метода beginTransaction(). Дальше идёт какой-то код запросов. Затем мы вызываем метод commit(), чтобы подтвердить наши изменения. Если же что-то пошло не так, то в блоке catch мы вызываем метод rollBack(), который вернёт все наши данные в предыдущее состояние.
"А зачем собственно нужны эти транзакции?" - спросите вы. Чтобы ответить на этот вопрос, рассмотрим пример, который я привёл выше. Там вы вставляем в поле "логин" значение login1, login2, login3.
Представим, что после того, как вставились login1 и login2, произошла какая-то ошибка. Получится, что эти данные вставлены, а login3 - нет. Во многих случаях это недопустимо и нарушит работу приложения в будущем.
Как раз для предотвращения таких ситуаций и нужны транзакции. Если наш скрипт дал сбой, то метод rollBack() вернёт всё в первоначальный вид. Т.е. login1 и login2 также не будут вставлены. Давайте сэмулируем эту ошибку.
try { $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $db->beginTransaction(); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES('login1')"); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES('login2')"); exit('error'); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES('login3')"); $db->commit(); } catch(PDOException $e) { $db->rollBack(); }
После вставки login1 и login2 мы выходим из скрипта с помощью функции exit(). У нас выбрасывается исключение, мы попадаем в блок catch, а там мы возвращаем всё в первоначальный вид. Теперь, если мы посмотрим в базу данных, то не увидим там login1 и login2.
На этом моменте мы закончим. Очевидно, что здесь мы разобрали далеко не всё, что предоставляет нам PDO, однако узнали основы работы с ним. Более подробную информацию о данном расширении вы всегда можете найти на официальном сайте PHP.
Материал подготовил Владислав Андреев специально для сайта CodeHarmony.ru
P.S. Хотите двигаться дальше в освоении PHP и ООП? Обратите внимание на премиум-уроки по различным аспектам сайтостроения, включая программирование на PHP, а также на бесплатный курс по созданию своей CMS-системы на PHP с нуля с использованием ООП:
Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!
Смотрите также: