Використання PDO для доступу до БД MySQL з PHP
ADO в Delphi AJAX Android C++ CakePHP CMS COM CSS Delphi Flash Flex HTML Internet Java JavaScript MySQL PHP RIA SCORM Silverlight SQL UML XML Бази даних Веб-розробка Генетичні алгоритми ГІС Гітара Дизайн Економіка Інтелектуальні СДН Колір Масаж Математика Медицина Музика Нечітка логіка ООП Патерни Подання знань Розкрутка сайту, SEO САПР Сесії в PHP Системне програмування Системний аналіз Тестологія Тестування ПЗ Фреймворки Штучний інтелект
|
Знання
Використання PDO для доступу до БД MySQL з PHPБезліч PHP-розробників звикли використовувати для роботи з базами даних розширення mysql і mysqli. Але з версії 5.1 в PHP існує більш зручний спосіб — PHP Data Objects. Цей клас, скорочено іменується PDO, надає методи для роботи з об'єктами і prepared statements, які помітно підвищать вашу продуктивність! Введення в PDO«PDO — PHP Data Objects — це прошарок, який пропонує універсальний спосіб роботи з декількома базами даних.» Турботу про особливості синтаксису різних СУБД вона залишає розробнику, але робить процес переключення між платформами набагато менш болючим. Нерідко для цього потрібно лише змінити рядок підключення до бази даних.
![]() Ця стаття написана для людей, які користуються mysql і mysqli, щоб допомогти їм у переході на більш потужний і гнучкий PDO. Підтримка СУБДЦе розширення може підтримувати будь-яку систему управління базами даних, для якої існує PDO-драйвер. На момент написання статті доступні наступні драйвера:
Втім, не всі з них є на вашому сервері. Побачити список доступних драйверів можна так:
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. Винятки та PDOPDO вміє викидати виключення при помилках, тому все повинно знаходитися в блоці 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 [0] вставиться на місце першого placeholder'а, $data [1] — на місце другого, і т.д. Але будьте уважні: якщо ваші індекси збиті, це працювати не буде. Іменні 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(). Перед його викликом бажано явно вказати, в якому вигляді вони вам потрібні. Є кілька варіантів:
$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('/[az]/', '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 (це величезний модуль!), Залишити без згадки наступні кілька функцій не можна. Метод -> 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 { # виводимо повідомлення про те, що задовольняючих запиту даних не знайдено } } Зверніть увагу на додаткові посиланняГоловний розділзагрузка...
|
Сторінки, близькі за змістом
|
Copyright © 2008—2023 Портал Знань.
При використанні матеріалів посилання, для інтернет-ресурсів — гіперпосилання, на Znannya.org обов'язкове.
Зв'язок
|
НТУУ "КПІ" Інженерія програмного забезпечення КПІ Лабораторія СЕТ |
|