Php запрос delete pdo примеры. PHP PDO — работаем с базами данных правильно

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

Введение

Начнем сначала PHP Data Objects(PDO) – легкий интерфейс для доступа к базам данных в языке PHP. Он может работать с большинством баз данных, такими как MS SQL ,Firebird, MySQL , Oracle, PostgreSQL , SQLite и другими. Но тут необходимо обратить внимание, что PDO предоставляет необходимый функционал для работы с базами данных, но для каждого типа базы данных должен быть установлен свой драйвер доступа для базы данных в виде расширения PHP.

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

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

Формат вот такой:

тип_базы_данных:host=имя_хоста;db=name

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

try { $db = new PDO("mysql:host=localhost;dbname=test" , "root" , "" ) ; $rows = $db -> exec ("CREATE TABLE `testing`(id INT PRIMARY KEY AUTO_INCREMENT, fname VARCHAR(20) NOT NULL DEFAULT "", email VARCHAR(50) NOT NULL DEFAULT "")" ) ; } catch(PDOException $e ) { die ("Error: " . $e -> getMessage () ) ; }

Если же в SQL выражении вы допустили ошибку, в PDO есть специальные функции:

errorCode() – возвращает номер ошибки, и

errorInfo() – возвращает массив, в котором, как номер ошибки, так и текст описания

Запросы непосредственно можно делать двумя функциями:

exec() и query()

Отличие их состоит в типе возвращаемого результата, exec возвращает количество затронутых в результате выполнения запроса строк, а вторая, возвращает результат запроса в объекте PDOStatement, о нем поговорим чуть ниже.

Теперь добавим эти функции в код и сделаем пример чуть более сложным:

// в начале конфиг define ("DB_DRIVER" , "mysql" ) ; define ("DB_HOST" , "localhost" ) ; define ("DB_NAME" , "test" ) ; define ("DB_USER" , "root" ) ; define ("DB_PASS" , "" ) ; try { // соединяемся с базой данных $connect_str = DB_DRIVER . ":host=" . DB_HOST . ";dbname=" . DB_NAME; $db = new PDO($connect_str , DB_USER, DB_PASS) ; // вставляем несколько строк в таблицу из прошлого примера $rows = $db -> exec ("INSERT INTO `testing` VALUES (null, "Ivan", "[email protected]"), (null, "Petr", "[email protected]"), (null, "Vasiliy", "[email protected]") " ) ; $error_array = $db -> errorInfo () ; if ($db ->
" ; // если запрос был выполнен успешно, // то выведем количество затронутых строк if ($rows ) echo "Количество затронутых строк: " . $rows . "
" ; // теперь выберем несколько строчек из базы $result = $db -> query ("SELECT * FROM `testing` LIMIT 2" ) ; // в случае ошибки SQL выражения выведем сообщене об ошибке $error_array = $db -> errorInfo () ; if ($db -> errorCode () != 0000) echo "SQL ошибка: " . $error_array [ 2 ] . "

" ; // теперь получаем данные из класса PDOStatement while ($row = $result -> fetch () ) { // в результате получаем ассоциативный массив print_r ($row ) ; } } catch(PDOException $e ) { die ("Error: " . $e -> getMessage () ) ; }

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

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

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

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

И так для начала создадим подготовленное выражение, это делается функцией Prepare()

В качестве параметра она принимает SQL запрос, но в нем, вместо значений, которые необходимо менять, ставятся псевдо переменные, которые могут быть в виде знака вопроса(?), либо имени псевдо переменой, которое начинается с двоеточия (:)

$sth1 = $db->prepare(“SELECT * FROM `testing` WHERE id=:id”);

$sth2 = $db->prepare(“SELECT * FROM `testing` WHERE id=?”);

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

Если вы определили переменные знаком вопроса, то потом, в функцию execute передайте массив значений, в той, последовательности, в которой стоят переменные.

Если же вы обозначили переменные именами, то надо будет назначить каждой переменной значение посредством функций:

bindValue() – присваивает псевдопеременной значение

bindParam() – связывает псевдопеременную с настоящей переменной, и при изменении настоящей переменной, не нужно больше вызывать никаких дополнительных функций, можно сразу execute()

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


Обратите внимание, что после создания объектом PDO подготовленного выражения в классе PDOStatement, мы пользуемся только им, соответственно, в нем есть свои функции errorCode, errorInfo, а также результат выполнения запросов, также сразу же хранится в нем.

А теперь второй способ.

Для присваивания значения псевдо переменной, воспользуемся функцией bindValue()

Этот код можно записать еще проще, связав псевдопеременную с реальной:

Тут же необходимо добавить, что очень желательно (чтобы не возникало лишних ошибок) третьим параметром указывать тип переменной. У меня лично, в случае отсутствия типа переменной, возникали ошибки в операторе WHERE, так как он считал переменную текстом, а не числом.

$sth3->bindParam(‘:id’,$id, PDO::PARAM_INT);

$sth3->bindParam(‘:id’,$id, PDO::PARAM_STR);

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

Транзакции

Транзакция – это совокупность запросов базу данных, которые должны быть обязательно выполнены все. Если какой-либо запрос не выполнен или выполнен с ошибкой, то транзакция отменяется и изменений данных в базе не происходит.

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

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

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

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

$db->beginTransaction();

После этого выполняем столько запросов к базе данных сколько необходимо сделать в этой транзакции.

И только после того как все запросы будут выполнены, Вы можете подтвердить транзакцию функцией

$db->commit();

или отменить транзакцию

$db->rollback();

Вот небольшой пример транзакций:

try { $connect_str = DB_DRIVER . ":host=" . DB_HOST . ";dbname=" . DB_NAME; $db = new PDO($connect_str , DB_USER, DB_PASS) ; $rows = $db -> exec ("CREATE TABLE `testing`(id INT PRIMARY KEY AUTO_INCREMENT, fname VARCHAR(20) NOT NULL DEFAULT "", email VARCHAR(50) NOT NULL DEFAULT "", money INT NOT NULL DEFAULT 0) ENGINE=InnoDB;" ) ; $rows = $db -> exec ("INSERT INTO `testing` VALUES (null, "Ivan", "[email protected]", 15000), (null, "Petr", "[email protected]", 411000), (null, "Vasiliy", "[email protected]", 1500000) " ) ; // Попробуем от Ивана перевести сумму 50000 // Петру $summ = 50000 ; $transaction = true ; $db -> beginTransaction () ; $sth1 = $db -> query ("SELECT money FROM testing WHERE fname="Ivan"" ) ; $sth2 = $db -> query ("SELECT money FROM testing WHERE fname="Petr"" ) ; $row1 = $sth1 -> fetch () ; $row2 = $sth2 -> fetch () ; if (! $row1 || ! $row2 ) $transaction = false ; $total2 = $summ + $row2 [ "money" ] ; $total1 = $row1 [ "money" ] - $summ ; if ($total1 < 0 || $total2 < 0) $transaction = false ; $num_rows1 = $db -> exec ( . $total1 . "" WHERE fname="Ivan"" ) ; $num_rows2 = $db -> exec ("UPDATE `testing` SET money="" . $total2 . "" WHERE fname="Petr"" ) ; if ($transaction ) { echo "Транзакция успешно прошла" ; $db -> commit () ; } else { echo "Транзакция не прошла" ; $db -> rollback () ; } } catch(PDOException $e ) { die ("Error: " . $e -> getMessage () ) ; }

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

В заключении хотелось бы сказать, что это еще далеко не полный мануал по PDO. Всю самую свежую и полную информацию Вы всегда можете раздобыть вот здесь: http://www.php.net/manual/en/book.pdo.php

Изучайте и создавайте.

Термин 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 выглядит так:

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

    Для подключения к базе данных нужно создать новый объект 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 execute([$id])->fetch(PDO::FETCH_OBJ); }

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

    $users = ;

    for ($i = 1 ; $i execute ([ $id ] ) -> fetch (PDO:: FETCH_OBJ ) ;

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

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

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

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

    • Перевод

    Множество PHP-разработчиков привыкли использовать для работы с базами данных расширения mysql и mysqli. Но с версии 5.1 в PHP существует более удобный способ - PHP Data Objects . Этот класс, сокращенно именуемый PDO, предоставляет методы для работы с объектами и prepared statements , которые заметно повысят вашу продуктивность!

    Введение в PDO«PDO – PHP Data Objects – это прослойка, которая предлагает универсальный способ работы с несколькими базами данных.»
    Заботу об особенностях синтаксиса различных СУБД она оставляет разработчику, но делает процесс переключения между платформами гораздо менее болезненным. Нередко для этого требуется лишь изменить строку подключения к базе данных.


    Эта статья написана для людей, которые пользуются mysql и mysqli, чтобы помочь им в переходе на более мощный и гибкий PDO.Поддержка СУБД Это расширение может поддерживать любую систему управления базами данных, для которой существует PDO-драйвер. На момент написания статьи доступны следующие драйвера:
    • PDO_CUBRID (CUBRID)
    • 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 and win32 ODBC))
    • PDO_PGSQL (PostgreSQL)
    • PDO_SQLITE (SQLite 3 and SQLite 2)
    • PDO_SQLSRV (Microsoft SQL Server)
    • 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-операции и использовать механизм исключений (об этом чуть дальше).

    $DBH расшифровывается как «database handle» и будет использоваться на протяжении всей статьи.

    Закрыть любое подключение можно путем переопределения его переменной в null.
    # закрывает подключение $DBH = null;
    Больше информации по теме отличительных опций разных СУБД и методах подключения к ним можно найти на php.net .

    Исключения и 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);
    Но стоит заметить, что ошибка при попытке соединения будет всегда вызывать исключение.PDO::ERRMODE_SILENT Это режим по умолчанию. Примерно то же самое вы, скорее всего, используете для отлавливания ошибок в расширениях mysql и mysqli. Следующие два режима больше подходят для DRY программирования.PDO::ERRMODE_WARNING Этот режим вызовет стандартный Warning и позволит скрипту продолжить выполнение. Удобен при отладке.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")->execute(); } catch(PDOException $e) { echo "Хьюстон, у нас проблемы."; file_put_contents("PDOErrors.txt", $e->getMessage(), FILE_APPEND); }
    В SQL-выражении есть синтаксическая ошибка, которая вызовет исключение. Мы можем записать детали ошибки в лог-файл и человеческим языком намекнуть пользователю, что что-то случилось.Insert и Update Вставка новых и обновление существующих данных являются одними из наиболее частых операций с БД. В случае с PDO этот процесс обычно состоит из двух шагов. (В следующей секции все относится как к UPDATE, так и INSERT)


    Тривиальный пример вставки новых данных:
    # STH означает "Statement Handle" $STH = $DBH->prepare("INSERT INTO folks (first_name) values ("Cathy")"); $STH->execute();
    Вообще-то можно сделать то же самое одним методом exec(), но двухшаговый способ дает все преимущества prepared statements. Они помогают в защите от SQL-инъекций, поэтому имеет смысл их использовать даже при однократном запросе.Prepared StatementsИспользование prepared statements укрепляет защиту от SQL-инъекций.
    Prepared statement - это заранее скомпилированное SQL-выражение, которое может быть многократно выполнено путем отправки серверу лишь различных наборов данных. Дополнительным преимуществом является невозможность провести SQL-инъекцию через данные, используемые в placeholder’ах.

    Ниже находятся три примера prepared statements.
    # без placeholders - дверь SQL-инъекциям открыта! $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values ($name, $addr, $city)"); # безымянные placeholders $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (?, ?, ?)"); # именные placeholders $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (:name, :addr, :city)");
    Первый пример здесь лишь для сравнения, его стоит избегать. Разница между безымянными и именными placeholder’ами в том, как вы будете передавать данные в prepared statements.

    Безымянные placeholder’ы # назначаем переменные каждому placeholder, с индексами от 1 до 3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $city); # вставляем одну строку $name = "Daniel" $addr = "1 Wicked Way"; $city = "Arlington Heights"; $STH->execute(); # вставляем еще одну строку, уже с другими данными $name = "Steve" $addr = "5 Circle Drive"; $city = "Schaumburg"; $STH->execute();
    Здесь два шага. На первом мы назначаем всем placeholder’ам переменные (строки 2-4). Затем назначаем этим переменным значения и выполняем запрос. Чтобы послать новый набор данных, просто измените значения переменных и выполните запрос еще раз.

    Если в вашем SQL-выражении много параметров, то назначать каждому по переменной весьма неудобно. В таких случаях можно хранить данные в массиве и передавать его:
    # набор данных, которые мы будем вставлять $data = array("Cathy", "9 Dark and Twisty Road", "Cardiff"); $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (?, ?, ?)"); $STH->execute($data);
    $data вставится на место первого placeholder’а, $data - на место второго, и т.д. Но будьте внимательны: если ваши индексы сбиты, это работать не будет.

    Именные placeholder’ы # первым аргументом является имя placeholder’а # его принято начинать с двоеточия # хотя работает и без них $STH->bindParam(":name", $name);
    Здесь тоже можно передавать массив, но он должен быть ассоциативным. В роли ключей должны выступать, как можно догадаться, имена placeholder’ов.
    # данные, которые мы вставляем $data = array("name" => "Cathy", "addr" => "9 Dark and Twisty", "city" => "Cardiff"); $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (:name, :addr, :city)"); $STH->execute($data);
    Одним из удобств использования именных placeholder’ов является возможность вставки объектов напрямую в базу данных, если названия свойств совпадают с именами параметров. Вставку данных, к примеру, вы можете выполнить так:
    # класс для простенького объекта 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("Cathy","9 Dark and Twisty","Cardiff"); # а тут самое интересное $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (:name, :addr, :city)"); $STH->execute((array)$cathy);
    Преобразование объекта в массив при execute() приводит к тому, что свойства считаются ключами массива.Выборка данных

    Данные можно получить с помощью метода ->fetch(). Перед его вызовом желательно явно указать, в каком виде они вам требуются. Есть несколько вариантов:
    • PDO::FETCH_ASSOC: возвращает массив с названиями столбцов в виде ключей
    • PDO::FETCH_BOTH (по умолчанию): возвращает массив с индексами как в виде названий стобцов, так и их порядковых номеров
    • 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.
    # поскольку это обычный запрос без placeholder’ов, # можно сразу использовать метод query() $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->addr = preg_replace("//", "x", $this->addr); $this->other_data = $other; } }
    При создании объекта все латинские буквы в нижнем регистре должны замениться на 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 Rosebud’, то на выходе получится ’5 Rxxxxxx’.

    Конечно, иногда будет требоваться, чтобы конструктор вызывался ПЕРЕД присваиванием значений. 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"));
    Можно даже передавать разные аргументы каждому объекту:
    $i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) { // что-то делаем $i++; }

    Другие полезные методы Хотя эта статья не может (и не пытается) охватить все аспекты работы с PDO (это огромный модуль!), оставить без упоминания следующие несколько функций нельзя.
    $DBH->lastInsertId();
    Метод ->lastInsertId() возвращает id последней вставленной записи. Стоит заметить, что он всегда вызывается у объекта базы данных (в статье он именуется $DBH), а не объекта с выражением ($STH).
    $DBH->exec("DELETE FROM folks WHERE 1"); $DBH->exec("SET time_zone = "-8:00"");
    Метод ->exec() используется для операций, которые не возвращают никаких данных, кроме количества затронутых ими записей.
    $safe = $DBH->quote($unsafe);
    Метод ->quote() ставит кавычки в строковых данных таким образом, что их становится безопасно использовать в запросах. Пригодится, если вы не используете prepared statements.
    $rows_affected = $STH->rowCount();
    Метод ->rowCount() возвращает количество записей, которые поучаствовали в операции. К сожалению, эта функция отказывалась работать с SELECT-запросами вплоть до PHP 5.1.6. Если обновить версию PHP не представляется возможным, количество записей можно получить так:
    $sql = "SELECT COUNT(*) FROM folks"; if ($STH = $DBH->query($sql)) { # проверяем количество записей if ($STH->fetchColumn() > 0) { # делаем здесь полноценную выборку, потому что данные найдены! } else { # выводим сообщение о том, что удовлетворяющих запросу данных не найдено } } Заключение Надеюсь, этот материал поможет кому-то из вас осуществить миграцию с расширений mysql и mysqli. Introduction

    Optionally, the --with-mysql-sock[=DIR] sets to location to the MySQL unix socket pointer for all MySQL extensions, including PDO_MYSQL. If unspecified, the default locations are searched.

    Optionally, the --with-zlib-dir[=DIR] is used to set the path to the libz install prefix.

    $ ./configure --with-pdo-mysql --with-mysql-sock=/var/mysql/mysql.sock

    Changelog Version Description
    5.4.0 mysqlnd became the default MySQL library when compiling PDO_MYSQL. Previously, libmysqlclient was the default MySQL library.
    5.4.0 MySQL client libraries 4.1 and below are no longer supported.
    5.3.9 Added SSL support with mysqlnd and OpenSSL.
    5.3.7 Added SSL support with libmysqlclient and OpenSSL.
    Predefined Constants

    The constants below are defined by this driver, and will only be available when the extension has been either compiled into PHP or dynamically loaded at runtime. In addition, these driver-specific constants should only be used if you are using this driver. Using driver-specific attributes with another driver may result in unexpected behaviour. PDO::getAttribute() may be used to obtain the PDO::ATTR_DRIVER_NAME attribute to check the driver, if your code can run against multiple drivers.

    PDO::MYSQL_ATTR_USE_BUFFERED_QUERY (integer ) If this attribute is set to TRUE on a PDOStatement , the MySQL driver will use the buffered versions of the MySQL API. If you"re writing portable code, you should use PDOStatement::fetchAll() instead.

    Example #1 Forcing queries to be buffered in mysql

    PDO::MYSQL_ATTR_LOCAL_INFILE (integer )

    Enable LOAD LOCAL INFILE .

    PDO::MYSQL_ATTR_INIT_COMMAND (integer )

    Command to execute when connecting to the MySQL server. Will automatically be re-executed when reconnecting.

    Note, this constant can only be used in the driver_options array when constructing a new database handle.

    PDO::MYSQL_ATTR_READ_DEFAULT_FILE (integer )

    Read options from the named option file instead of from my.cnf . This option is not available if mysqlnd is used, because mysqlnd does not read the mysql configuration files.

    PDO::MYSQL_ATTR_READ_DEFAULT_GROUP (integer )

    Read options from the named group from my.cnf or the file specified with MYSQL_READ_DEFAULT_FILE . This option is not available if mysqlnd is used, because mysqlnd does not read the mysql configuration files.

    PDO::MYSQL_ATTR_MAX_BUFFER_SIZE (integer )

    Maximum buffer size. Defaults to 1 MiB. This constant is not supported when compiled against mysqlnd.

    PDO::MYSQL_ATTR_DIRECT_QUERY (integer )

    Perform direct queries, don"t use prepared statements.

    PDO::MYSQL_ATTR_FOUND_ROWS (integer )

    Return the number of found (matched) rows, not the number of changed rows.

    PDO::MYSQL_ATTR_IGNORE_SPACE (integer )

    Permit spaces after function names. Makes all functions names reserved words.

    PDO::MYSQL_ATTR_COMPRESS (integer )

    Enable network communication compression. This is also supported when compiled against mysqlnd as of PHP 5.3.11.

    PDO::MYSQL_ATTR_SSL_CA (integer )

    The file path to the SSL certificate authority.

    This exists as of PHP 5.3.7.

    PDO::MYSQL_ATTR_SSL_CAPATH (integer )

    The file path to the directory that contains the trusted SSL CA certificates, which are stored in PEM format.

    This exists as of PHP 5.3.7.

    PDO::MYSQL_ATTR_SSL_CERT (integer )

    The file path to the SSL certificate.

    This exists as of PHP 5.3.7.

    PDO::MYSQL_ATTR_SSL_CIPHER (integer )

    A list of one or more permissible ciphers to use for SSL encryption, in a format understood by OpenSSL. For example: DHE-RSA-AES256-SHA:AES128-SHA

    This exists as of PHP 5.3.7.

    PDO::MYSQL_ATTR_SSL_KEY (integer )

    The file path to the SSL key.

    This exists as of PHP 5.3.7.

    PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT (integer )

    Provides a way to disable verification of the server SSL certificate.

    This exists as of PHP 7.0.18 and PHP 7.1.4.

    PDO::MYSQL_ATTR_MULTI_STATEMENTS (integer )

    Disables multi query execution in both PDO::prepare() and PDO::query() when set to FALSE .

    Note, this constant can only be used in the driver_options array when constructing a new database handle.

    This exists as of PHP 5.5.21 and PHP 5.6.5.

    Runtime Configuration

    The behaviour of these functions is affected by settings in php.ini .

    PDO_MYSQL Configuration Options Name Default Changeable
    pdo_mysql.default_socket "/tmp/mysql.sock" PHP_INI_SYSTEM
    pdo_mysql.debug NULL PHP_INI_SYSTEM
    For further details and definitions of the PHP_INI_* modes, see the .

    Here"s a short explanation of the configuration directives.

    Sets a Unix domain socket. This value can either be set at compile time if a domain socket is found at configure. This ini setting is Unix only.

    Pdo_mysql.debug boolean

    Enables debugging for PDO_MYSQL. This setting is only available when PDO_MYSQL is compiled against mysqlnd and in PDO debug mode.

    Table of Contents
    • PDO_MYSQL DSN - Connecting to MySQL databases

    Than install them

    rpm -Uvh remi-release-26.rpm
    rpm -Uvh epel-release-6-8.noarch.rpm

    Know you can use remi repository to gest php-pdo and php-mysql.

    yum --enablerepo=remi install php-pdo
    yum --enablerepo=remi install php-mysql

    Restart the Apache

    systemctl stop httpd
    systemctl start httpd

    Good to go!

    10 years ago

    SQLSTATE: General error: 2014 Cannot execute queries while other unbuffered queries are active. ...

    This one can be a royal pain to deal with. Never stack statements to be executed in one go. Nobody ever mentions this possibility in all the posts I"ve seen dealing with this error.

    This example is a Zend Framework example but the theory is the same.


    This will run fine but PDO will balk with the "unbuffered" error if you follow this with another query.


    Chopping it into individual queries fixes the problem.

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

    Введение в 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 "Нет строк соответствующих запросу."; } }

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