Проста обгортка для PDO
Взагалі, через те, що бібліотека PDO сама по собі вже є обгорткою, вигадати якісь поліпшення для неї досить важко. Спроби новачків розширити функціонал рідко призводять до чогось розумного чи корисного. Проте трохи покращити цю бібліотеку можна.
Проблема N1, багатослівністьГоловний недолік і PDO, і mysqli при роботі з підготовленими виразами полягає в тому, що їх вбудовані функції заточені на множинне виконання підготовленого запиту (коли prepare викликається лише раз, а потім багато разів) викликається execute() з різними даними). Через це вони такі багатослівні. Але біда в тому, що на практиці РНР виконувати такі запити доводиться досить рідко. І в результаті більшості запитів доводиться щоразу писати непотрібний код: $stmt = $pdo -> prepare ($ sql); $stmt -> execute ($params); $data = $stmt -> fetch(); Що називається – за що боролися, на те й напоролися. Жодного скорочення коду в порівнянні з пам'ятною mysql_query() не відбулося. А дуже хотілося б! При цьому Wes Furlong підклав користувачам PDO ще одну свиню - execute() повертає тупо бульове значення замість того, щоб повертати стейтмент, що дозволило б реалізувати method chaining і отримувати красивий код виду $data = $pdo -> prepare ( $sql )-> execute ($params)-> fetch(); Але, на жаль, навіть такий підхід майже недоступний. Та й у будь-якому випадку він надмірний, оскільки в більшості випадків нам не треба робити ні prepare, ні execute - нам треба тупо виконати чортовий запит, передавши в нього чортові дані для плейсхолдерів.
Тому, щоб скоротити кількість писанини, додамо до PDO одну функцію, run(), вся функція якої зводитиметься наведеному вище коду - виконатиprepare/execute і повернути стейтмент: class MyPDO extends PDO public function run ( $sql , $args = NULL ) $stmt = $this -> prepare ($ sql); $stmt -> execute ($ args); return $stmt; > > А вже зі стейтменту ми можемо отримати будь-які дані, будь-яким стандартним способом:
$data = $pdo -> run ( "SELECT * FROM users WHERE sex='male'" )-> fetchAll ();
Проблема N2, доступністьЩе одним неприємним відкриттям для новачків є те, що до ПДО не можна звернутись у будь-якому місці скрипту, як до mysql_query().
Тому наступним покращенням буде реалізація доступу до ПДО через статичний синглтон. Цей патерн часто лають в інтернеті, і за справу. Але тут треба розуміти одну просту річ: Якщо ваш код схильний до тих проблем, які може породити синглтон - значить, ви вже користуєтеся високорівневим драйвером БД, швидше за все зі складу популярно фремворка. Але якщо ви тільки-но вилізли з печери з mysql_query(), звикнувши писати її по всьому коду не дбаючи про передачу з'єднання, то необхідність тягати за собою інстанс PDO стане серйозним випробуванням. При тому, що і сам синтаксис PDO, і підготовлених виразів і власними силами утворюють не кволий такий поріг входження. Тож спробуємо підсолодити пігулку можливістю звернутися до БД із будь-якого місця скрипту, як у старі добрі часи.
У результаті у нас вийшла дуже компактна надбудова над PDO, яка, будучи такою ж простою у використанні, як і mysql_query(), при цьому скорочує код і забезпечує безпеку підготовлених виразів.
КодPDO :: ERRMODE_EXCEPTION , PDO :: ATTR_DEFAULT_FETCH_MODE => PDO :: FETCH_ASSOC , PDO :: ATTR_EMULATE_PREPARES => TRUE , ); $dsn = 'mysql:host=' .DB_HOST . ';dbname=' . DB_NAME . ';charset=' . DB_CHAR ; self :: $instance = new PDO ($dsn, DB_USER, DB_PASS, $opt); > повернути себе :: $екземпляр ; >
публічна статична функція __callStatic ( $method , $args ) return call_user_func_array (array( self :: instance (), $method), $args ); >
public static function run ( $sql , $args = []) if (! $args ) return self :: instance ()-> запит ($sql); > $stmt = self :: instance ()-> підготувати ($sql); $stmt -> виконати ($args); повернути $stmt ; > >
Примери# Создаем таблицу DB :: query ( "CREATE temporary TABLE pdowrapper (id int auto_increment primary key, name varchar(255))" );
# множене виконання підготовлених виражень $stmt = DB :: pripravi ("INSERT INTO pdowrapper VALUES (NULL, ?)"); foreach ([ 'Sam' , 'Bob' , 'Joe' ] as $name ) $stmt -> виконати ([ $name ]); > var_dump ( DB :: lastInsertId ()); //рядок(1) "3"
# Отримання строки в циклі $stmt = DB :: run ( "SELECT * FROM pdowrapper" ); while ( $row = $stmt -> fetch ( PDO :: FETCH_LAZY )) echo $ row ['name'], "," ; echo $row -> ім'я , "," ; echo $row [ 1 ], PHP_EOL ; > /* Сем,Сем,Сем Боб,Боб,Боб Джо,Джо,Джо */
# Отримання однієї строки $id = 1 ; $row = DB :: run ( "SELECT * FROM pdowrapper WHERE id=?" , [ $id ])-> вибірка (); var_export ($row); /* масив ( 'id' => '1', 'name' => 'Сем', ) */
# Отримання одного поля $name = DB :: run ( "SELECT name FROM pdowrapper WHERE id=?" , [ $id ])-> fetchColumn (); var_dump ( $name ); //string(3) "Сем"
# Отримання всіх рядків у масиві $all = DB :: run ( "SELECT name, id FROMpdowrapper" )-> fetchAll ( PDO :: FETCH_KEY_PAIR ); var_export ( $all ); /* array ( 'Sam' => '1', ' Bob' => '2', 'Joe' => '3', ) */
# Оновлення таблиці $new = 'Sue'; $stmt = DB :: run ("UPDATE pdowrapper SET name=? WHERE id=?", [$new, $id]); var_dump ( $stmt -> rowCount ()); //int(1)