Pdo підставити параметри без виконання запиту. Як працювати з PDO? Повне керівництво. Вставка до бази даних, метод exec()

З'єднання з базою данихвстановлюється тоді, коли створюється екземпляр класу PDO. Не має значення, який драйвер Ви хочете використати; Вам завжди потрібно використовувати клас PDO. Його конструктор приймає параметри для визначення джерела бази даних (відомий як DSN), і необов'язкові параметри для імені користувача і пароля.

З'єднання з MySQL:

$dbh = новий 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 = новий PDO("mysql:host=localhost;dbname=test", $user, $pass); // Тут щось робимо: ... // А тепер, увага: кінець зв'язку! $ dbh = null;

Багато веб-програм виграють від створення постійних з'єднань із серверами баз даних. Постійні з'єднання не закриваються, коли скрипт завершує роботу, а кешуються і знову використовуються, коли інший скрипт просить з'єднання, використовуючи самі облікові дані для з'єднання. Кеш постійних з'єднань дозволяє уникнути накладних витрат на встановлення нового з'єднання щоразу, коли скрипт повинен спілкуватися з базою даних, внаслідок чого веб-програми працюють швидше.

Встановлення постійного з'єднання:

$dbh = новий PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

Майте на увазі:Якщо Ви хочете використовувати постійне з'єднання, Ви повинні встановити PDO::ATTR_PERSISTENTу масиві опцій драйвера, що передається конструктору класу PDO. Встановлюючи цей атрибут через PDO::setAttribute() після створення екземпляра об'єкта, драйвер не використовуватиме постійні зв'язки. А так само, в цьому випадку вам не вдасться розширити клас PDOStatement для якихось своїх потреб, тобто. не можна буде встановити: PDO::ATTR_STATEMENT_CLASS

Я думаю настав час підвищити свій експірієнс і перейти при роботі з базою даних з mysql_ функцій на PDO. Ця бібліотека є потужним та швидким доповненням до PHP. Одна з її переваг - робота з багатьма базами даних (MS SQL, MySQL, PostgreSQL, Oracle та ін.). Відмінною характеристикою цієї бібліотеки є підготовлені вирази, так звані prepared statements, які повинні прискорити роботу з базою, а головне зробити обмін даними безпечними та забути про такі вразливості як sql-enjection. Крім того, є й інші корисні можливості. У цій статті я спробував зібрати приклади робіт, за якими можна відразу зрозуміти суть роботи PDO.

У PHP існують три розширення для роботи з базою MySQL: mysql, mysqli та PDO. PHP PDO (PHP Data Objects) включено до PHP 5.1 і вище. Як я зрозумів, на сьогоднішній момент функції для роботи з базою даних mysql_ не рекомендують до використання, тому що розробка php_mysql зупинилася на підтримці функціоналу MySQL 4.1.3. і також не підтримує транзакції, об'єктний інтерфейс і схильне до уразливостей при підстановці значень у запит. Після mysql_ з'явилося розширення mysqli (MySQL Improved у 5 версії), яке підтримує нові можливості MySQL та використовує як ОПП синтаксис так і процедурне програмування. Усі ці бібліотеки використовують стандартну клієнтську бібліотеку MySQL (libmysql). У цій же статті давайте на живих прикладах подивимося як здійснюється робота з mysql, за допомогою найсвіжішого розширення - PDO.

PDO З'єднання з БД

//приклад з'єднання з MySQL за допомогою PDO $db = new PDO("mysql:host=localhost;dbname=test", $user, $pass);

Як тільки буде встановлено успішне з'єднання з конкретним сервером бази даних, буде повернено об'єкт PDO. Цей об'єкт дозволяє виконувати найрізноманітніші завдання баз даних.

Якщо є якісь помилки підключення, то спрацює механізм виключень – PDOException. Потрібно завжди обертати операції PDO у блок try/catch. Ви можете зловити виняток, якщо ви хочете обробляти помилки, або ви можете залишити його для глобального обробника винятків (exception), які ви створили за допомогою set_exception_handler(). У PDO є спеціальні функції для помилок: errorCode() – поверне номер помилки, errorInfo() – поверне масив із номером помилки та описом. Вони потрібні оскільки за умовчанням режим роботи з помилками стоїть ERRMODE_SILENT. У цьому випадку, щоб побачити ці помилки, доведеться їх викликати:

Echo $conn->errorCode(); echo $conn->errorInfo();

Щоб цього не робити, в режимі розробки простіше одразу виставити потрібний режим роботи з помилками: ATTR_ERRMODE та ERRMODE_EXCEPTION. Також можна прописати кодування роботи з базою. У результаті в нас вийде такий код підключення:

Try ( $db = новий PDO("mysql:host=$host;dbname=$dbname", $user, $password); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db-> exec("set names utf8"); ) catch(PDOException $e) ( echo $e->getMessage(); )

Після успішного підключення до бази даних екземпляр класу PDO повертається до сценарію. $db містить дескриптор бази даних. З'єднання залишається активним протягом життя об'єкта PDO. Щоб закрити з'єднання, потрібно знищити об'єкт з гарантією, що всі інші посилання на нього будуть видалені. Зробити це можна шляхом присвоєння змінної, що містить об'єкт значення NULL. Якщо ви не зробите цього явно, PHP автоматично закриватиме з'єднання після завершення роботи скрипта.

//Закриття з'єднання $db = null;

Багато веб-програм виграють від створення постійних підключень до серверів баз даних. Постійні з'єднання не закриваються в кінці скрипту, а кешуються і повторно використовуються, коли інший сценарій запитує з'єднання, використовуючи самі облікові дані. Постійне з'єднання дозволяє зменшити ресурси на створення нового з'єднання кожного разу, коли сценарій повинен звернутися до бази даних, що призводить до більш швидкої роботи веб-програми.

//Постійне з'єднання $dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

Тепер, коли ви побачили, як відкривати та закривати з'єднання, давайте розглянемо інші приклади роботи з PDO. У цьому випадку я маю намір показати вам, як виконувати запити до конкретної бази даних. Запити можна виконувати трьома функціями: exec(), query() і prepare+execute.

Exec()

Перший – exec поверне лише кількість задіяних рядків або FALSE при помилці і використовується там, де не повертаються дані, наприклад при видаленні:

//використання методу exec() try( $db = new PDO("mysql:host=localhost;dbname=test","user","password"); $delrows=$db->exec("DELETE FROM users WHERE id>20"); echo "Кількість віддалених рядків: ".$delrows; ) catch(PDOException $e)( echo "Error: ".$e->getMessage(); exit(); ) //Ще $db- >exec("DELETE FROM folks WHERE 1"); //або $db->exec("SET time_zone = "-8:00""); //або $db->exec("CREATE TABLE `test`(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL DEFAULT "", email VARCHAR(50) NOT NULL DEFAULT "")"); //або $db->exec("SET CHARACTER SET utf8");

Query()

Другий – query() поверне результат в об'єкті PDOStatement. Також повертає результат або FALSE за помилки. Йому можна довірити найпростіші запити. Можна використовувати query() з умовою (я правда не знаю навіщо комусь це може знадобитися), але тоді все одно доведеться екранувати дані методом PDO::quote

//Прості запити $db->query("SET CHARACTER SET utf8"); $db->query("SELECT * FROM users"); //Можна обчислити кількість рядків $stmt = $db->query("SELECT * FROM table"); $row_count = $stmt->rowCount(); echo $row_count."rows selected"; //Ще варіант із кількістю $stmt = $db->query("SELECT * from users"); $rows = $stmt->fetchAll(); $ count = count ($ rows); foreach($rows as $row) ( print_r($row); ) //Запит з умовою та екрануванням $conn->query("SELECT * FROM table WHERE id = ". $conn->quote($id));

lastInsertId()повертає ідентифікатор останнього вставленого рядка бази даних.

//метод lastInsertId() повертає id останнього запису $db->query("INSERT INTO users SET name="Vasya",address="Here",email=" [email protected]""); $insertId=$db->lastInsertId();

Підготовлені висловлювання – prepared statments.

Третій спосіб - prepare+execute - Підготовлені вирази, вони ж підготовлені інструкції вони ж плейсхолдери вони ж prepared statmentsабо змінні, що зв'язуються, дозволяють визначити вираз один раз, а потім багаторазово його виконувати з різними параметрами. Також вони дозволяють відокремити змінні від запиту, що робить код безпечнішим і підвищує швидкість виконання. У вашому коді більше не треба буде намагатися очистити дані, що передаються. Ми зробимо це лише один раз перед виконанням запиту до БД. Для цього використовуємо функцію Prepare(); Як параметр вона приймає SQL запит, але у ньому, замість змінних використовуються мітки, як знака питання '?' чи номерів ':1', чи зміною, ім'я якої починається з двокрапки ':'. Якщо ви зупинилися на знаках питання (:цифрах), то вам потрібно в функцію execute передати масив значень у відповідній послідовності. Якщо ваш вибір іменовані змінні, то треба призначити кожній змінній значення через одну з двох функцій: або bindValue(), яка присвоює псевдо-змінне значення, або bindParam(), яка пов'язує псевдо-змінну зі справжньою змінною. Третім параметром можна вказати тип змінної, наприклад $db->bindParam(':id',$id, PDO::PARAM_INT).

//Не іменовані мітки try ( $stmt = $db->prepare("INSERT INTO test (label,color) VALUES (?,?)"); $stmt -> execute(array("perfect","green") ); ) catch(PDOException $e)( echo "Error: ".$e->getMessage(); exit(); ) //stmt - це "дескриптор стану" //Іменовані мітки $stmt = $db->prepare ("INSERT INTO test (label,color) VALUES (:label,:color)"); $stmt -> execute(array("label"=>"perfect", "color"=>"green")); //Ще варіант $stmt = $db->prepare("INSERT INTO users (firstname, lastname, email) VALUES (:firstname, :lastname, :email)"); $stmt->bindParam(":firstname", $firstname); $stmt->bindParam(":lastname", $lastname); $stmt->bindParam(":email", $email); $firstname = "John"; $lastname = "Smith"; $email = " [email protected]$stmt->execute();

Ще раз нагадаю, що якщо ви не використовуєте підготовлені вирази, але все-таки хочете убезпечити передані дані, то це можна зробити за допомогою функції PDO:quote.

PDO SELECT даних

Для вибірки даних використовують методи fetch() або fetchAll(). Перед викликом функції потрібно вказати PDO як Ви діставатимете дані з бази. PDO::FETCH_ASSOC поверне рядки у вигляді асоціативного масиву з іменами полів як ключі. PDO::FETCH_NUM поверне рядки у вигляді числового масиву. За замовчуванням вибірка відбувається з PDO::FETCH_BOTH, який дублює дані як з чисельними, так і з асоціативними ключами, тому рекомендується вказати один спосіб, щоб не мати дублюючих масивів:

$stmt = $db->query("SELECT * from users"); //Установка fetch mode $stmt->setFetchMode(PDO::FETCH_ASSOC); while($row = $stmt->fetch()) ( echo "

" . $row["firstname"] . " " . $row["lastname"] .

"; echo"

" . $row["email"] . "


"; }

Або можна вказати метод вибірки в методі ->fetch()

$stmt = $db->query("SELECT * FROM table"); while($row = $stmt->fetch(PDO::FETCH_ASSOC)) ( echo $row["field1"]." ".$row["field2"]; //і т.д... ) // Увага, що не працює приклад з LIKE! $stmt = $db->prepare("SELECT field FROM table WHERE field LIKE %?%"); $stmt->bindParam(1, $search, PDO::PARAM_STR); $stmt->execute(); //Потрібно так: $stmt = $db->prepare("SELECT field FROM table WHERE field LIKE ?"); $stmt->bindValue(1, "%$search%", PDO::PARAM_STR); $stmt->execute(); //Ще приклад $stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?"); $stmt->bindValue(1, $id, PDO::PARAM_INT); $stmt->bindValue(2, $name, PDO::PARAM_STR); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); //Ще варіант $stmt = $db->prepare("SELECT * from users"); $stmt -> execute(); while($row = $stmt->fetch()) ( print_r($row); )

PDO UPDATE даних

Відбувається сутнісно як і INSERT і SELECT (у разі знову будемо використовувати іменовані мітки (placeholders)):

$stmt = $db->prepare("UPDATE users set email = :email where lastname=:lastname"); $stmt->bindParam(":lastname", $lastname); $stmt->bindParam(":email", $email); $lastname = "Smith"; $email = " [email protected]$stmt->execute();

DELETEВидалення відбувається найпростішим чином:

$db->exec("DELETE FROM users");

Звичайно, ви можете також використовувати іменовані параметри (placeholders) при видаленні.

Якщо у вас є часто використовувані заготівлі при роботі з розширенням PHP PDO, буду вдячний якщо ви ними поділитеся. Посилання на мануал

Якщо у вас виникла помилка Undefined variable: DBH … то можете почитати, як це виправити.

Google допоміг знайти шпаргалку по PDO, може кому знадобиться:

PDO (PHP Data Objects) – розширення PHP, яке реалізує взаємодію з базами даних за допомогою об'єктів. Профіт у тому, що немає прив'язки до конкретної системи управління базами даних. PDO підтримує СУБД: MySQL, PostgreSQL, SQLite, Oracle, Microsoft SQL Server та інші.

Чому варто використовувати PDO

Функції MySQL в PHP для роботи з БД давно вже застаріли, на сьогоднішній день бажано використовувати MySQL або PDO (PHP Data Objects). Крім того, mysqli - ця бібліотека, яка за великим рахунком, не призначена для прямого використання в коді. Вона може бути хорошим будівельним матеріалом для створення бібліотеки вищого рівня. При роботі з mysqli слід також пам'ятати про безпеку вашої програми, зокрема про захист від SQL-ін'єкцій. У разі використання PDO (з його підготовленими запитами) такий захист йде вже "з коробки", головне правильно застосувати необхідні методи.

Тестова база даних із таблицею

// З консолі Windows mysql> CREATE DATABASE `pdo-test` CHARACTER SET utf8 COLLATE utf8_general_ci; USE pdo-тест; CREATE TABLE categories (ID INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), name VARCHAR(255) NOT NULL); INSERT INTO `categories` (`name`) VALUES ("Ноутбуки та планшети"), ("Комп'ютери та периферія"), ("Комплектуючі для ПК"), ("Смартфони та смарт-годинник"), ("Телевізори та медіа "), ("Ігри та приставки"), ("Аудіотехніка"), ("Фото-відеоапаратура"), ("Офісна техніка та меблі"), ("Мережеве обладнання"), ("Велика побутова техніка"), ( "Товари для кухні"), ("Краса і здоров'я"), ("Товари для дому"), ("Інструменти"), ("Автотовари");

Встановлення PDO

// Встановлення в Linux sudo apt update sudo apt install php7.2-mysql sudo apt-get install pdo-mysql // У php.ini додати extension=pdo.so extension=pdo_mysql.so // На Windows, як правило, драйвер вже встановлений, потрібно просто перевірити, чи він включений в php.ini extension=php_pdo_mysql.dll

Перевірити доступні драйвери

print_r(PDO::getAvailableDrivers());

З'єднання з базою даних

З'єднання встановлюються автоматично під час створення об'єкта PDO з його базового класу.

// Приклад #1. Просте підключення $db = new PDO("mysql:host=localhost;dbname=pdo", "root", "password");

За помилки підключення PHP видасть помилку:

Fatal error: Uncaught PDOException: ... // Приклад #2. Обробка помилок підключення try ( $dbh = new PDO("mysql:host=localhost;dbname=pdo", "root", "password"); ) catch (PDOException $e) ( print "Error!: " . $e- >getMessage(); die(); )

У цьому прикладі підключення ми використовуємо конструкцію try...catch. Багато хто сперечається про доцільність її використання. Особисто я використовую try...catch, вона мені не заважає.

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

У PDO два способи виконання запитів:

  • Прямий – складається з одного кроку;
  • Підготовлений – складається із двох кроків.

Прямі запити

  • query() використовується для операторів, які не вносять зміни, наприклад, SELECT . Повертає об'єкт PDOStatemnt , з якого за допомогою методів fetch() або fetchAll вилучаються результати запиту. Можна його порівняти з mysql resource, який повертала mysql_query().
  • exec() використовується для операторів INSERT, DELETE, UPDATE. Повертає кількість опрацьованих запитом рядків.

Прямі запити використовуються лише в тому випадку, якщо у запиті відсутні змінні та є впевненість, що запит безпечний та правильно екранований.

$stmt = $db->query("SELECT * FROM categories"); while ($row = $stmt->fetch()) ( echo "

"; print_r($row); )

Підготовлені запити

Якщо ж у запит передається хоча б одна змінна, цей запит обов'язково повинен виконуватися лише через підготовлені висловлювання. Що це означає? Це стандартний SQL запит, у якому замість змінної ставиться спеціальний маркер - плейсхолдер. PDO підтримує позиційні плейсхолдери (?), для яких важливий порядок змінних, що передаються, і іменовані (:name), для яких порядок не важливий. Приклади:

$sql = "SELECT name FROM categories WHERE id = ?"; $sql = "SELECT name FROM categories WHERE name = :name";

Щоб виконати такий запит, спочатку треба підготувати його за допомогою методу prepare() . Вона також повертає PDO statement, але ще без даних. Щоб їх отримати, треба виконати цей запит, попередньо передавши наші змінні. Передати можна двома способами: Найчастіше можна просто виконати метод execute(), передавши йому масив зі змінними:

$stmt = $pdo->prepare("SELECT `name` FROM categories WHERE `id` = ?"); $stmt->execute([$id]); $stmt = $pdo->prepare("SELECT `name` FROM categories WHERE `name` = :name"); $stmt->execute(["name" => $name]);

Як бачимо, у разі іменованих плейсхолдерів в execute() повинен передаватися масив, у якому ключі повинні збігатися з іменами плейсхолдерів. Після цього можна отримати результати запиту:

$ id = 1; $stmt = $db->prepare("SELECT * FROM categories WHERE `id` = ?"); $stmt->execute([$id]); $category = $stmt->fetch(PDO::FETCH_LAZY); echo "

"; print_r($category);

ВАЖЛИВО!Підготовлені запити – основна причина використовувати PDO, оскільки це єдиний безпечний спосіб виконання SQL запитів, у яких беруть участь змінні.

Отримання даних. Метод fetch()

Ми вже познайомилися з методом fetch() , який служить для послідовного отримання рядків з БД. Цей метод є аналогом функції mysq_fetch_array() і їй подібних, але діє інакше: замість безлічі функцій тут використовується одна, але її поведінка задається переданим параметром. У подробицях про ці параметри буде написано в , а як коротку рекомендацію пораджу застосовувати fetch() в режимі FETCH_LAZY

$ id = 1; $stmt = $db->prepare("SELECT * FROM categories WHERE `id` = ?"); $stmt->execute([$id]); while ($row = $stmt->fetch(PDO::FETCH_LAZY)) ( echo "Category name: ".$row->name; )

У цьому режимі не витрачається зайва пам'ять, і до того ж до колонок можна звертатися будь-яким із трьох способів через індекс, ім'я, або властивість (через ->). Недоліком цього режиму є те, що він не працює з fetchAll()

Отримання даних. Метод fetchColumn()

Також PDO statement має метод для отримання значення єдиної колонки. Дуже зручно, якщо ми просимо лише одне поле - у цьому випадку значно скорочується кількість коду:

$ id = 1; $stmt = $db->prepare("SELECT `name` FROM categories WHERE `id` = ?"); $stmt->execute([$id]); $name = $stmt->fetchColumn(); echo "Category name: ".$name;

Отримання даних. Метод fetchAll()

$data = $db->query("SELECT * FROM categories")->fetchAll(PDO::FETCH_ASSOC); foreach ($data as $k => $v)( echo "Category name: ".$v["name"]."
"; }

PDO та оператор LIKE

Працюючи із підготовленими запитами, слід розуміти, що плейсхолдер може замінювати тількирядок чи число. Ні ключове слово, ні ідентифікатор, ні частина рядка чи набір рядків через плейсхолдер підставити не можна. Тому для LIKE необхідно спочатку підготувати рядок пошуку повністю, а потім його підставляти у запит:

$search = "комп"; $query = "SELECT * FROM categories WHERE `name` LIKE?"; $params = ["%$search%"]; $stmt = $db->prepare($query); $stmt->execute($params); $data = $stmt->fetchAll(PDO::FETCH_ASSOC); $i = 1; foreach ($data as $category)( echo $i++ . ". " . $category["name"]."
"; }

Тут може виникнути проблема! Пошук може не працювати, тому що з бази у вас надходять дані в неправильному кодуванні. Необхідно додати кодування на підключення, якщо воно там не вказане!

$db = новий PDO("mysql:host=localhost;dbname=pdo;charset=utf8", "root", "");

PDO та оператор LIMIT

Важливо!Коли PDO працює в режимі емуляції, всі дані, які були передані безпосередньо в execute(), форматуються як рядки. Тобто, ескейп і обрамляються лапками. Тому LIMIT?,? перетворюється на LIMIT "10", "10" і очевидно викликає помилку синтаксису і, відповідно, порожній масив даних.

Рішення #1: Вимкнути режим емуляції:

$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Рішення #2: Біндіть ці цифри через bindValue() , примусово виставляючи їм тип PDO::PARAM_INT:

$limit = 3; $stm = $db->prepare("SELECT * FROM categories LIMIT?"); $stm->bindValue(1, $limit, PDO::PARAM_INT); $stm->execute(); $data = $stm->fetchAll(); echo "

"; print_r($data);

PDO та оператор IN

Під час вибірки з таблиці необхідно діставати записи, відповідні всім значенням масиву.

$arr =; $in = str_repeat("?,", count($arr) - 1) . "?"; $sql = "SELECT * FROM categories WHERE `id` IN ($in)"; $stm = $db->prepare($sql); $stm->execute($arr); $data = $stm->fetchAll(); echo "

"; print_r($data);

Додавання записів

$name = "Нова категорія"; $query = "INSERT INTO `categories` (`name`) VALUES(:name)"; $params = [ ":name" => $name ]; $stmt = $pdo->prepare($query); $stmt->execute($params);

Зміна записів

$ id = 1; $name = "Змінений запис"; $query = "UPDATE `categories` SET `name` = :name WHERE `id` = :id"; $params = [ ":id" => $id, ":name" => $name ]; $stmt = $pdo->prepare($query); $stmt->execute($params);

Видалення записів

$ id = 1; $query = "DELETE FROM `categories` WHERE `id` = ?"; $params = [$id]; $stmt = $pdo->prepare($query); $stmt->execute($params);

Використання транзакцій

try ( // Початок транзакції $pdo->beginTransaction(); // ... code // Якщо в результаті виконання нашого коду все пройшло успішно, // то зафіксуємо цей результат $pdo->commit(); ) catch (Exception $e) ( // Інакше, відкотимо транзакцію. $pdo->rollBack(); echo "Помилка: " . $e->getMessage(); )

Важливо! Транзакції в PDO працюють лише з таблицями InnoDB

У цій нотатці ми познайомилися з основними поняттями 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 = новий 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"); , $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 "Немає рядків відповідних запиту." ; ) )

Сподіваюся, що урок Вам сподобався!

  • Переклад

Багато 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 і 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! .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

Використання попереднього стану зміцнює захист від 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.