Использование update одной колонки в pdo php. Настройка и использование PDO — расширения PHP Data Objects для работы с базами данных. Создание PDO объекта

Фреймворк Bootstrap: быстрая адаптивная вёрстка

Пошаговый видеокурс по основам адаптивной верстки в фреймворке Bootstrap.

Научитесь верстать просто, быстро и качественно, используя мощный и практичный инструмент.

Верстайте на заказ и получайте деньги.

Бесплатный курс "Сайт на WordPress"

Хотите освоить CMS WordPress?

Получите уроки по дизайну и верстке сайта на WordPress.

Научитесь работать с темами и нарезать макет.

Бесплатный видеокурс по рисованию дизайна сайта, его верстке и установке на CMS WordPress!

*Наведите курсор мыши для приостановки прокрутки.

Назад Вперед

Основы работы с расширением 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 .

Давайте посмотрим, как мы теперь можем подключиться к базе:

$db = new PDO("mysql:host=$host;dbname=$db", $user, $password);

$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; // Объект 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;

Однако Fetch возвращает только одну запись, поэтому, если мы хотим получить все записи, то надо использовать FetchAll .

$stmt = $db->query("SELECT * FROM users"); $result = $stmt->FetchAll(PDO::FETCH_ASSOC); foreach($result as $user) { echo $user["name"]."
"; }

Но есть ещё одна классная штука, связанная с Fetch . С ее помощью мы можем заполнить наш класс данными из БД автоматически .

Class User { public $login; public $id; public function showInfo() { echo "".$this->id.""." : ".$this->login."
"; } } $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()."
"; 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.

Материал подготовил Владислав Андреев специально для сайта сайт

P.S. Хотите двигаться дальше в освоении PHP и ООП? Обратите внимание на премиум-уроки по различным аспектам сайтостроения, включая программирование на PHP, а также на бесплатный курс по созданию своей CMS-системы на PHP с нуля с использованием ООП:

Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!


Сегодня я начинаю цикл статей, посвящённых PDO , в котором мы разберём, что такое PDO , зачем он нам нужен и как его использовать.

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

Что такое PDO?

PDO(PHP Data Objects) - это просто интерфейс , позволяющий нам абстрагироваться от конкретной базы данных. Лучше всего показать на примере.

Mysql_connect($host, $user, $pass); // MySQL
mysql_select_db($db);

Sqlite_open($db); // sqlite

Pg_connect("host=$host, dbname=$db, user=$user, password=$pass"); // PostgreSQL

В коде выше представлены способы для подключения к трём разным базам данных: MySQL , sqlite и PostgreSQL . Как видите, функции у каждой БД отличаются.

То же самое с другими действиями. Например, выборка данных из БД.

$sql = "INSERT INTO(name, pass) VALUES($name, $pass)";

Mysql_query($sql); // MySQL
sqlite_query($sql); // sqlite
pg_query($sql); // PostgreSQL

Зачем нужен PDO?

Представим, что у нас есть огромная база данных PostgreSQL , и мы решили сменить её на MySQL . Нам придётся переписывать очень много кода, и, скорее всего, без ошибок не обойдётся. Чтобы решить эту проблему и существует PDO , позволяющий нам не зависеть от конкретной базы.

Давайте рассмотрим, как мы теперь можем подключиться.

$db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); // MySQL
$db = new PDO("sqlite:host=$host;dbname=$db", $user, $pass); // sqlite
$db = new PDO("pgsql:host=$host;dbname=$db", $user, $pass); // PostgreSQL

Как видно из кода выше, в этих трёх подключениях меняется только строчка с названием БД, а остальное всё то же самое.

Чтобы что-нибудь выбрать, мы можем написать так:

$db->exec($sql);

Всё! Запрос выполнится независимо от того, какая у нас база данных.

Поддержка

PDO доступен с PHP 5.1 . Чтобы мы могли "забыть", какую базу данных мы используем, за нас всё делают их драйверы . Чтобы их активировать, зайдите в файл php.ini и найдите там строчки, которые начинаются на extension=php_pdo_ , а затем идёт название базы данных, и раскоментируйте их.

На этом всё для вступительной статьи, а в следующей мы уже начнём разбираться, как использовать PDO .

Обеспечивает методы для подготовки выражений и работы с объектами, которые могут сделать Вашу работу более продуктивной!

Введение в PDO

"PDO - PHP Data Objects - это уровень для доступа к базам данных, который обеспечивает унифицированные методы для доступа к различным базам данных."

Он не зависит от специфического синтаксиса базы данных и позволяет легко переключаться на другой тип баз данных и платформу простым изменением строки подключения в большинстве случаев.

Данный урок не является описанием процесса работы с SQL . Он предназначен для тех, кто использует расширения mysql или mysqli , чтобы помочь им перейти к более мощному и портируемому PDO.

Поддержка баз данных

Расширение поддерживает любую базу данных, для которой есть PDO драйвер. На текущий момент доступны драйвера для следующих типов баз данных:

  • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
  • PDO_FIREBIRD (Firebird/Interbase 6)
  • PDO_IBM (IBM DB2)
  • PDO_INFORMIX (IBM Informix Dynamic Server)
  • PDO_MYSQL (MySQL 3.x/4.x/5.x)
  • PDO_OCI (Oracle Call Interface)
  • PDO_ODBC (ODBC v3 (IBM DB2, unixODBC и win32 ODBC))
  • PDO_PGSQL (PostgreSQL)
  • PDO_SQLITE (SQLite 3 и SQLite 2)
  • PDO_4D (4D)

Для работы системы достаточно установить только те драйвера, которые действительно нужны. Получить список драйверов, доступных в системе можно следующим образом:

Print_r(PDO::getAvailableDrivers());

Подключение

Различные базы данных могут иметь немного различающиеся методы подключения. Ниже показаны методы подключения к нескольким популярным баз данных. Можно заметить, что первые три идентичны друг другу, и только SQLite имеет специфический синтаксис.


try { # MS SQL Server и Sybase с PDO_DBLIB $DBH = new PDO("mssql:host=$host;dbname=$dbname, $user, $pass"); $DBH = new PDO("sybase:host=$host;dbname=$dbname, $user, $pass"); # MySQL с PDO_MYSQL $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); # SQLite $DBH = new PDO("sqlite:my/database/path/database.db"); } catch(PDOException $e) { echo $e->getMessage(); }

Обратите внимание на блок try/catch - всегда нужно оборачивать операции PDO в блок try/catch и использовать механизм исключений. Обычно выполняется только одно подключение, в нашем примере показаны несколько подключений для отображения синтаксиса. $DBH содержит дескриптор базы данных и будет использоваться на протяжении всего нашего урока.

Вы можете закрыть любое соединение установкой дескриптора в null .

# Закрываем соединение $DBH = null;

Вы можете узнать больше о специфических опциях и строках подключения для различных баз данных из документов с сайта PHP.net .

Исключения и PDO

PDO может использовать исключения для обработки ошибок. Значит все операции PDO должны быть заключены в блок try/catch . PDO может выдавать ошибки трех уровней, уровень контроля ошибок выбирается установкой атрибута режима контроля ошибок для дескриптора базы данных:

$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Вне зависимости от установленного уровня контроля ошибка соединения всегда вызывает исключение и поэтому всегда должна быть заключена в блок try/catch .

PDO::ERRMODE_SILENT

Уровень контроля ошибок, устанавляваемы по умолчанию. На этом уровене ошибки генерируются по такому же принципу, как в расширениях mysql или mysqli . Два других уровня контроля ошибок более подходят для стиля програмирования в стиле DRY (Don"t Repeat Youself - не повторяй сам себя).

PDO::ERRMODE_WARNING

На данном уровне контроля ошибок генеррируются стандартные предупреждения PHP, при этом программа может продолжать выполение. Данный уровень удобен для отладки.

PDO::ERRMODE_EXCEPTION

Данный уровень контроля ошибок следует использовать в большинстве ситуаций. Генерируются исключения, которые позволяют аккуратно обрабатывать ошибки и скрывать данные, которые могут помочь кому-нибудь взломать Вашу систему. Ниже приведен пример, демонстрирующий преимущества исключений:

# Подключаемся к базе данных try { $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); # Ошибочно набираем DELECT вместо SELECT! $DBH->prepare("DELECT name FROM people"); } catch(PDOException $e) { echo " Извините. Но операция не может быть выполнена."; file_put_contents("PDOErrors.txt", $e->getMessage(), FILE_APPEND); }

Здесь сделана преднамеренная ошибка в выражении SELECT. Это вызовет исключение. Исключение отправит описание ошибки в log файл и выдаст сообщение пользователю.

Вставка и обновление данных

Вставка новых данных или обновление существующих - одна из наиболее часто используемых общих операций баз данных. При использовании PDO, она раскладывается на два этапа. Все, что описана в данной главе применимо и к обоим операциям UPDATE и INSERT .


Здесь приведен пример наиболее используемого типа вставки данных:

# STH - это "дескриптор состояния" $STH = $DBH->prepare("INSERT INTO folks (first_name) values ("Cathy")"); $STH->execute();

Конечно, вы можете выполнить данную операцию с использованием метода exec() , при этом количество вызовов будет меньше на один. Но лучше использовать более длинный метод для получения преимуществ подготовленных выражений. Даже если Вы собираетесь использовть их один единственный раз, подготовленные выражения помогут Вам защититься от атак на Вашу систему.

Подготовленные выражения

Подготовленные выражения - это предварительно скомпилированные выражения SQL, которые могут быть выполнены много раз с помощью пересылки только данных на сервер. Они имеют дополнительное преимущество при автоматическом заполнении шаблона данными в виде защиты от атаки посредством вложений SQL кода.

Вы можете использовать подготовленные выражения с помощью включения шаблонов в ваш код SQL. Ниже приводятся 3 примера: один без шаблонов, один с неименованными шаблонами, один с именоваными шаблонами.

# нет шаблонов - открыто для атак путем внедрения SQL кода! $STH = $DBH->("INSERT INTO folks (name, addr, city) values ($name, $addr, $city)"); # неименованые шаблоны $STH = $DBH->("INSERT INTO folks (name, addr, city) values (?, ?, ?); # именованые шаблоны $STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)");

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

Неименованные шаблоны

# назначение переменных каждому шаблону, индексируются от 1 до 3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $city); # Вставляем одну строку $name = "Дима" $addr = "ул. Лизюкова"; $city = "Москва"; $STH->execute(); # Вставляем другую строку $name = "Сеня" $addr = "Коммунистический тупик"; $city = "Питер"; $STH->execute();

Операция проходит в два этапа. На первом этапе шаблонам назначаются переменные. Затем, пременным присваиваются значения и выполняем выражение. Чтобы послать следующую порцию данных, нужно изменить значения переменных и выполнить выражение снова.

Выглядит несколько громоздко для выражений с большим количеством параметров? Конечно. Однако, если Ваши данные храняться в массиве, то все будет очень коротко:

# Данные, которые надо вставить $data = array("Моня", "проспект Незабудок", "Закутайск"); $STH = $DBH->("INSERT INTO folks (name, addr, city) values (?, ?, ?)"); $STH->execute($data);

Данные в массиве подставляются в шаблоны в порядке следования. $data идет в первый шаблон, $data - во второй, и так далее. Однако, если массив проиндексирован в другом порядке, то такая операция будет выполняться некорректно. Вам нужно следить за соответствием порядка следования шаблонов и порядком расположения данных в массиве.

Именованные шаблоны

Вот пример использования именованного шаблона:

# Первый аргумент функции - имя именованного шаблона # Именованный шаблон всегда начинается с двоеточия $STH->bindParam(":name", $name);

Вы можете использовать сокращения, но они работают с ассоциированными массивами. Пример:

# Данные, которые надо вставить $data = array("name" => "Мишель", "addr" => "переулок Кузнечный", "city" => "Cnjkbwf"); # Сокращение $STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)"); $STH->execute($data);

Ключи Вашей таблицы не нуждаются в двоеточии, но тем не менее должны соответствовать именам шаблонов. Если Вы используете массив массивов, то можно проходить по нему и просто вызывать execute для каждого массива данных.

Другая приятная особенность именованых шаблонов - способность вставлять объекты прямо в вашу базу данных, при совпадении свойств и имен полей. Пример:

# Простой объект class person { public $name; public $addr; public $city; function __construct($n,$a,$c) { $this->name = $n; $this->addr = $a; $this->city = $c; } # и т.д. ... } $cathy = new person("Катя","проспект Ленина","Можайск"); # Выполняем: $STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)"); $STH->execute((array)$cathy);

Преобразование типа объекта к array в execute приводит к обработке свойств как ключей массива.

Получение данных


Для получения данных используется метод идентификатора состояния ->fetch() . Перед вызовом метода fetch() нужно указать PDO как Вы будете доставать данные из базы. Можно выбрать следующие опции:

  • PDO::FETCH_ASSOC : возвращает массив, индексированный по именам столбцов
  • PDO::FETCH_BOTH (default) : возвращает массив, индексированный по именам столбцов и по номерам
  • PDO::FETCH_BOUND : назначает значения ваших столбцов набору переменных с использованием метода ->bindColumn()
  • PDO::FETCH_CLASS : назначает значения столбцов свойствам именованного класса, если соответствующего свойства не существует - оно создается
  • PDO::FETCH_INTO : обновляет существующий экземпляр именованного класса
  • PDO::FETCH_LAZY : комбинация PDO::FETCH_BOTH/PDO::FETCH_OBJ , создает имена переменных объекта так как они используются
  • PDO::FETCH_NUM : возвращает массив, индексированный по номерам столбцов
  • PDO::FETCH_OBJ : возвращает анонимный объект с именами свойств, соответствующих именам столбцов

В действительности основные ситуации разрешаются с помощью трех опций: FETCH_ASSOC , FETCH_CLASS и FETCH_OBJ . Для установки метода извлечения данных используется:

$STH->setFetchMode(PDO::FETCH_ASSOC);

Также можно устанавливать метод извлечения данных непосредственно в вызове метода ->fetch() .

FETCH_ASSOC

Данный тип извлечения данных создает ассоциативный массив, индексированный по именам столбцов. Он должен быть достаточно хорошо известен тем, кто пользуется расширениями mysql/mysqli . Пример выборки данных:

$STH = $DBH->query("SELECT name, addr, city from folks"); # Устанавливаем режим извлечения данных $STH->setFetchMode(PDO::FETCH_ASSOC); while($row = $STH->fetch()) { echo $row["name"] . "\n"; echo $row["addr"] . "\n"; echo $row["city"] . "\n"; }

Цикл while продолжает перебирать результат выборки по одной строке до полного завершения.

FETCH_OBJ

При данном типе извлечения данных создается объект класса std для каждой строки полученных данных:

$STH = $DBH->query("SELECT name, addr, city from folks"); # Устанавливаем режим извлечения данных $STH->setFetchMode(PDO::FETCH_OBJ); # показываем результат while($row = $STH->fetch()) { echo $row->name . "\n"; echo $row->addr . "\n"; echo $row->city . "\n"; }

FETCH_CLASS

При данном типе извлечения данные помещаются прямо в класс, который Вы выбирете. При использовании FETCH_CLASS свойства вашего объекта устанавливаются ДО вызова конструктора. Это очень важно. Если свойства соответствующего имени столбца не существует, то такое свойство будет создано (как public ) для Вас.

Это означает, что если данные нуждаются в трансформации после извлечения из базы данных, то она может быть выполнена автоматически Вашим объектом, как только таковой будет создан.

Например, представим ситуацию, когда адрес должен быть частично скрыт для каждой записи. Мы можем выполнить задачу с помощью оперирования свойством в конструкторе:

Class secret_person { public $name; public $addr; public $city; public $other_data; function __construct($other = "") { $this->address = preg_replace("//", "x", $this->address); $this->other_data = $other; } }

Как только данные извлечены в класс, все символы a-z в нижнем регистре в адресе будут заменены символом x. Теперь с использованием класса и получением данных трансформация происходит полностью прозрачно:

$STH = $DBH->query("SELECT name, addr, city from folks"); $STH->setFetchMode(PDO::FETCH_CLASS, "secret_person"); while($obj = $STH->fetch()) { echo $obj->addr; }

Если адрес был ’Ленинский пр-т 5’ Вы увидите ’Лхххххххх хх-х 5’. Конечно, существуют ситуации, когда Вы хотите, чтобы конструктор был вызван перед тем, как будут назначены данные. PDO имеет средства реализовать это:

$STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "secret_person");

Теперь, когда Вы повторите предыдущий пример при установленом режиме PDO::FETCH_PROPS_LATE адрес не будет скрыт, так как конструктор был вызван и свойства назначены.

Если Вам нужно, то можно передавать аргументы конструктору при извлечении данных в объект:

$STH->setFetchMode(PDO::FETCH_CLASS, "secret_person", array("stuff"));

Если Вам нужно передать различные данные в конструктор для каждого объекта, Вы можете устанавливать режим извлечения данных внутри метода fetch :

$i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) { // do stuff $i++ }

Некоторые другие полезные методы

Так как в короткой статье нельзя описать PDO полностью, то представим несколько полезных методов для выполнения базовых операций.

$DBH->lastInsertId();

Метод ->lastInsertId() всегда вызывается дескриптором базы данных (а не дескриптором состояния) и возвращает значение автоматически увеличивающегося идентификатора последней вставленной строки для данного соединения.

$DBH->exec("DELETE FROM folks WHERE 1"); $DBH->exec("SET time_zone = "-8:00"");

Метод ->exec() используется для различных вспомогательных операций.

$safe = $DBH->quote($unsafe);

Метод ->quote() квотирует строки, так что они могут быть использованы в запросах. Это Ваш резерв на случай, если подготовленные выражения не используются.

$rows_affected = $STH->rowCount();

Метод ->rowCount() возвращает значение integer , указывающее количество строк, которые обрабатываются операцией. В последней версии PDO, в соответствии с отчетом об ошибках(http://bugs.php.net/40822) данный метод не работает с выражениями SELECT . Если у Вас возникли проблемы и Вы не можете обновить PHP, получить количество строк можно следующим способом:

$sql = "SELECT COUNT(*) FROM folks"; if ($STH = $DBH->query($sql)) { # Проверка количества строк if ($STH->fetchColumn() > 0) { # Здесь должен быть код SELECT } else { echo "Нет строк соответствующих запросу."; } }

Надеюсь, что урок Вам понравился!

Соединение с базой данных устанавливается тогда, когда создаётся экземпляр класса PDO. Не имеет значения, какой драйвер Вы хотите использовать; Вам всегда нужно будет использовать класс PDO. Его конструктор принимает параметры для того, чтобы определить источник базы данных (известный как DSN), и необязательные параметры для имени пользователя и пароля.

Соединение с MySQL:

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass);

Если произойдут какие либо ошибки соединения, то будет выброшено исключение: объект класса PDOException. Вы можете поймать его, если захотите обработать эту ситуацию, или можете оставить его для глобального обработчика исключений, который устанавливается через set_exception_handler ().

Обработка ошибок соединения:

try { $dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass); foreach($dbh->query(‘SELECT * from FOO’) as $row) { print_r($row); } $dbh = null; } catch (PDOException $e) { die("Ошибка! Всё. Приехали... ".$e->getMessage()); }

Внимание: Если Вы не поймаете исключение, брошенное конструктором PDO, действие по умолчанию, предпринятое движком zend, должно остановить скрипт и показать трассировку. Эта хрень выдаст все Ваши интимные подробности общения с базой данной. То есть покажет подробные детали соединения с базой данных, включая имя пользователя и пароль! На Вашей совести поймать это исключение, либо явно (через утверждение try catch ), либо неявно через set_exception_handler ().

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

Закрытие соединения:

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass); // Здесь что то делаем: ... // А теперь, внимание: конец связи! $dbh = null;

Многие веб-приложения выигрывают от создания постоянных соединений с серверами баз данных. Постоянные соединения не закрываются, когда скрипт завершает работу, а кэшируются и снова используются, когда другой скрипт просит соединения, используя те же учётные данные для соединения. Кэш постоянных соединений позволяет избежать накладных расходов на установление нового соединения каждый раз, когда скрипт должен общаться с базой данных, в результате чего веб-приложения работают быстрее.

Установка постоянного соединения:

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

Имейте ввиду: Если Вы хотите использовать постоянное соединение, Вы должны установить PDO::ATTR_PERSISTENT в массиве опций драйвера, который передаётся конструктору класса PDO. Устанавливая этот атрибут через PDO::setAttribute() после создания экземпляра объекта, драйвер не будет использовать постоянные связи. А так же, в этом случае вам не удастся расширить класс PDOStatement для каких то своих нужд, т.е. нельзя будет установить: PDO::ATTR_STATEMENT_CLASS

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

Почему не myqli или mysql?

Чаще всего, в отношении новых технологий, встает вопрос их преимуществ перед старыми-добрыми и проверенными инструментами, а также, перевода на них текущих и старых проектов.

Объектная ориентированность PDO

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

Говоря о 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 -i | grep "pdo"

Теперь откроем его в любом браузере и найдем нужные данные поиском по строке PDO .

Знакомимся с PDO

Процесс работы с PDO не слишком отличается от традиционного. В общем случае, процесс использования PDO выглядит так:

  1. Подключение к базе данных;
  2. По необходимости, подготовка запроса и связывание параметров;
  3. Выполнение запроса.

Подключение к базе данных

Для подключения к базе данных нужно создать новый объект PDO и передать ему имя источника данных, так же известного как DSN .

В общем случае, DSN состоит из имени драйвера, отделенного двоеточием от строки подключения, специфичной для каждого драйвера PDO .

Для MySQL , подключение выполняется так:

$connection = new PDO("mysql:host=localhost;dbname=mydb;charset=utf8", "root", "root");

$connection = new PDO ("mysql:host=localhost;dbname=mydb;charset=utf8" , "root" , "root" ) ;

В данном случае, DSN содержит имя драйвера mysql , указание хоста (возможен формат host=ИМЯ_ХОСТА:ПОРТ ), имя базы данных, кодировка, имя пользователя MySQL и его пароль.

Запросы

В отличие от mysqli_query() , в PDO есть два типа запросов:

  • Возвращающие результат (select, show );
  • Не возвращающие результат (insert , detele и другие).

Первым делом, рассмотрим второй вариант.

Выполнение запросов

Рассмотрим пример выполнения запроса на примере insert .

$connection->exec("INSERT INTO users VALUES (1, "somevalue"");

$connection -> exec () ;

Конечно же, данный запрос возвращает количество затронутых строк и увидеть его можно следующим образом.

$affectedRows = $connection->exec("INSERT INTO users VALUES (1, "somevalue""); echo $affectedRows;

$affectedRows = $connection -> exec ("INSERT INTO users VALUES (1, "somevalue"" ) ;

echo $affectedRows ;

Получение результатов запроса

В случае использования mysqli_query () , код мог бы быть следующим.

$result = mysql_query("SELECT * FROM users"); while($row = mysql_fetch_assoc($result)) { echo $row["id"] . " " . $row["name"]; }

$result = mysql_query ("SELECT * FROM users" ) ;

while ($row = mysql_fetch_assoc ($result ) ) {

Для PDO , код будет проще и лаконичнее.

foreach($connection->query("SELECT * FROM users") as $row) { echo $row["id"] . " " . $row["name"]; }

foreach ($connection -> query ("SELECT * FROM users" ) as $row ) {

echo $row [ "id" ] . " " . $row [ "name" ] ;

Режимы получения данных

Как и в 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 ), имя класса будет определено из значения первого столбца.

Примечание : это не полный список, все возможные константы и варианты их комбинации доступны в документации .

Пример получения ассоциативного массива:

$statement = $connection->query("SELECT * FROM users"); while($row = $statement->fetch(PDO::FETCH_ASSOC)) { echo $row["id"] . " " . $row["name"]; }

$statement = $connection ->

while ($row = $statement -> fetch (PDO:: FETCH_ASSOC ) ) {

echo $row [ "id" ] . " " . $row [ "name" ] ;

Примечание : Рекомендуется всегда указывать режим выборки, так как режим PDO:: FETCH_BOTH потребует вдвое больше памяти — фактически, будут созданы два массива, ассоциативный и обычный.

Рассмотрим использование режима выборки PDO:: FETCH_CLASS . Создадим класс User :

class User { protected $id; protected $name; public function getId() { return $this->id; } public function setId($id) { $this->id = $id; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } }

class User

protected $id ;

protected $name ;

public function getId ()

return $this -> id ;

public function setId ($id )

$this -> id = $id ;

public function getName ()

return $this -> name ;

public function setName ($name )

$this -> name = $name ;

Теперь выберем данные и отобразим данные при помощи методов класса:

$statement = $connection->query("SELECT * FROM users"); while($row = $statement->fetch(PDO::FETCH_CLASS, "User")) { echo $row->getId() . " " . $row->getName(); }

$statement = $connection -> query ("SELECT * FROM users" ) ;

while ($row = $statement -> fetch (PDO:: FETCH_CLASS , "User" ) ) {

echo $row -> getId () . " " . $row -> getName () ;

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

Для понимания сути и всех преимуществ связывания параметров нужно более подробно рассмотреть механизмы PDO . При вызове $statement -> query () в коде выше, PDO подготовит запрос, выполнит его и вернет результат.

При вызове $connection -> prepare () создается подготовленный запрос. Подготовленные запросы — это способность системы управления базами данных получить шаблон запроса, скомпилировать его и выполнить после получения значений переменных, использованных в шаблоне. Похожим образом работают шаблонизаторы Smarty и Twig .

При вызове $statement -> execute () передаются значения для подстановки в шаблон запроса и СУБД выполняет запрос. Это действие аналогично вызову функции шаблонизатора render () .

Пример использования подготовленных запросов в PHP PDO :

В коде выше подготовлен запрос выборки записи с полем id равным значению, которое будет подставлено вместо : id . На данном этапе СУБД выполнит анализ и компиляцию запроса, возможно с использованием кеширования (зависит от настроек).

Теперь нужно передать недостающий параметр и выполнить запрос:

$id = 5; $statement->execute([ ":id" => $id ]);

Преимущества использования связанных параметров

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

PDO предоставляет удобную возможность экранирования пользовательских данных, например, такой код больше не нужен:

Вместо этого, теперь целесообразно делать так:

Можно, даже, еще укоротить код, используя нумерованные параметры вместо именованных:

В тоже время, использование подготовленных запросов позволяет улучшить производительность при многократном использовании запроса по одному шаблону. Пример выборки пяти случайных пользователей из базы данных:

$numberOfUsers = $connection->query("SELECT COUNT(*) FROM users")->fetchColumn(); $users = ; $statement = $connection->prepare("SELECT * FROM users WHERE id = ? LIMIT 1"); for ($i = 1; $i <= 5; $i++) { $id = rand(1, $numberOfUsers); $users = $statement->execute([$id])->fetch(PDO::FETCH_OBJ); }

$numberOfUsers = $connection -> query ("SELECT COUNT(*) FROM users" ) -> fetchColumn () ;

$users = ;

for ($i = 1 ; $i <= 5 ; $i ++ ) {

$id = rand (1 , $numberOfUsers ) ;

$users = $statement -> execute ([ $id ] ) -> fetch (PDO:: FETCH_OBJ ) ;

При вызове метода prepare () , СУБД проведет анализ и скомпилирует запрос, при необходимости использует кеширование. Позже, в цикле for , происходит только выборка данных с указанным параметром. Такой подход позволяет быстрее получить данные, уменьшив время работы приложения.

При получении общего количества пользователей в базе данных был использован метод fetchColumn () . Этот метод позволяет получить значение одного столбца и является полезным при получении скалярных значений, таких как количество, сумма, максимально или минимальное значения.

Связанные значения и оператор IN

Часто, при начале работы с PDO , возникают трудности с оператором IN . Например, представим, что пользователь вводит несколько имен, разделенных запятыми. Пользовательский ввод хранится в переменной $names .