Для того, чтобы подключиться к нашей СУБД, как и в случае с использованием встроенных функций mysql_, нам необходим минимальный набор параметров: , адрес сервера для подключения, имя пользователя СУБД, пароль этого пользователя и имя базы данных, к которой мы будем подключаться.
Для удобства использования сохраним эти параметры в массив. О том, что такое классы и объекты в PHP вы должны иметь хоть какое-то представление. Иначе даже этот материал может быть не очень вам понятен.
Те, кому лень читать, могут сразу же скачать файл с сервера.
<?php // Массив значений параметров для подключения к СУБД $aParams = array( 'driver' => 'mysql', // Здесь указываем нужный нам драйвер 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); ?>
Теперь пора подключаться к СУБД. На странице документации PHP, относящейся к этой тематике, есть вся исчерпывающая информаия с примерами.
Там сказано, что подключаться с помощью PDO к СУБД MySQL нужно так:
<?php // Подключение к СУБД MySQL $dbh = new PDO( 'mysql:host=localhost;dbname=test', $user, $pass' ); ?>
Если у вас не MySQL-сервер, а например, MS SQL, используйте соответствующий драйвер, указав его имя в массиве параметров подключения.
Теперь изменим эту строку так, чтобы подключение происходило с нашими параметрами.
<?php // Массив значений параметров для подключения к СУБД $aParams = array( 'driver' => 'mysql', // Здесь указываем нужный нам драйвер 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); // Подключение к СУБД MySQL $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; $dbh = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ] ); ?>
Если все параметры указаны верно, подключение должно быть успешно установлено. Как проверить? Легко!
print "<pre>"; var_dump( $dbh ); print "</pre>";
Вы должны увидеть нечто следующее.
object(PDO)#1 (0) { }
Объект PDO создан. Всё хорошо. А давайте теперь намеренно укажем неверный пароль, просто добавив к нему нижнее подчеркивание.
<?php // Массив значений параметров для подключения к СУБД $aParams = array( 'driver' => 'mysql', // Здесь указываем нужный нам драйвер 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); // Подключение к СУБД MySQL $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; $dbh_bad = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ] . '_' ); ?>
Если у вас настроено отображение ошибок, класс PDO вам тут же покажет нечто такое:
Fatal error: Uncaught PDOException: SQLSTATE[HY000] [1045] Access denied for user 'user'@'localhost' (using password: YES) in /var/www/site.ru/document.php:30 Stack trace: #0 /var/www/site.ru/document.php(30): PDO->__construct('mysql:host=loca...', 'user', 'password_') #1 {main} thrown in /var/www/site.ru/document.php on line 30
Весьма информативно. Но для обработки ошибок лучше использовать свои функции и объекты. Пусть они наследуют свойства и методы встроенных в PHP, но будут свои. Сделаем так.
<?php // Массив значений параметров для подключения к СУБД $aParams = array( 'driver' => 'mysql', // Здесь указываем нужный нам драйвер 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); // Подключение к СУБД MySQL $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { $dbh_bad = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ] . '_' ); } catch( PDOException $e ) { } ?>
Мы намеренно указали неверные параметры для подключения, и это должно было вызвать фатальную ошибку, что привело бы к остановке всего сценария, вызвав исключение PDOException. Но зачастую останавливать работу всего сценария не хочется. Хочется просто увидеть сообщение об ошибке. Для этого и используется конструкция try — catch. Можете проверить, разместив любой PHP-код под конструкцией try — catch. Он будет работать.
Теперь давайте заглянем внутрь переменной $e из блока catch.
<?php // Массив значений параметров для подключения к СУБД $aParams = array( 'driver' => 'mysql', // Здесь указываем нужный нам драйвер 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); // Подключение к СУБД MySQL $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { $dbh_bad = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ] . '_' ); } catch( PDOException $e ) { print "<pre>"; var_dump( $e ); print "</pre>"; } ?>
Вы должны увидеть нечто похожее на это:
object(PDOException)#3 (8) { ["message":protected]=> string(86) "SQLSTATE[HY000] [1045] Access denied for user 'user'@'localhost' (using password: YES)" ["string":"Exception":private]=> string(0) "" ["code":protected]=> int(1045) ["file":protected]=> string(48) "/var/www/site.ru/document.php" ["line":protected]=> int(123) ["trace":"Exception":private]=> array(1) { [0]=> array(6) { ["file"]=> string(48) "/var/www/site.ru/document.php" ["line"]=> int(123) ["function"]=> string(11) "__construct" ["class"]=> string(3) "PDO" ["type"]=> string(2) "->" ["args"]=> array(3) { [0]=> string(41) "mysql:host=localhost;dbname=dbname" [1]=> string(4) "user" [2]=> string(10) "password_" } } } ["previous":"Exception":private]=> NULL ["errorInfo"]=> NULL }
Этот объект класса PDOException имеет очень много полезной информации. Давайте изменим наш код, чтобы выводить собственноручное сообщение об ошибке СУБД.
<?php // Массив значений параметров для подключения к СУБД $aParams = array( 'driver' => 'mysql', // Здесь указываем нужный нам драйвер 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); // Подключение к СУБД MySQL $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { $dbh_bad = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ] . '_' ); } catch( PDOException $e ) { $error = "<hr /><p style=\"background-color:red;\">Ошибка выполнения подключения к СУБД: <strong>" . $e->getCode() . "</strong>. Ошибка: <strong>" . $e->getMessage() . "</strong></p><hr />"; print $error; } ?>
Внутри переменной $e у нас объект исключения PDOException. Сообщение об ошибке можно получить с помощью его метода (так в объектах называются функции) getMessage(), а код ошибки — getCode().
Мы просто вывели на экран сообщение об ошибке, не прерывая работу сценария. Но это не очень правильно при попытке подключения к СУБД. Какой вообще смысл в дальнейшей работе всего сценария, если нет подключения к базе данных? Конкретно в этом случае логичнее вместо функции print() использовать функцию exit().
Значит давайте соответствующим образом изменим наш код. И сразу же сделаем так, чтобы мы не занимались каждый раз при обращении к базе данных формированием строки с сообщением об ошибке. А значит что мы будем делать для этого? Правильно! Мы объявим соответствующую функцию. Да не простую, а анонимную. Да не просто объявим, а присвоим её переменой!
<?php /** * Анонимной функции будет передан в качестве аргумента * объект типа PDOException */ $PDOFatalError = function( PDOException $e ) { $error = "<hr /><p style=\"background-color:red;\">Ошибка выполнения подключения к СУБД: <strong>" . $e->getCode() . "</strong>. Ошибка: <strong>" . $e->getMessage() . "</strong></p><hr />"; exit( $error ); }; // Массив значений параметров для подключения к СУБД $aParams = array( 'driver' => 'mysql', // Здесь указываем нужный нам драйвер 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { $dbh_bad = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ] . '_' ); } catch( PDOException $e ) { $PDOFatalError( $e ); } ?>
В общем-то, всё. Давайте заглянем внутрь подключенной базы данных, конечно же, подключившись к ней с корректными параметрами.
<?php /** * Анонимной функции будет передан в качестве аргумента * объект типа PDOException */ $PDOFatalError = function( PDOException $e ) { $error = "<hr /><p style=\"background-color:red;\">Ошибка выполнения подключения к СУБД: <strong>" . $e->getCode() . "</strong>. Ошибка: <strong>" . $e->getMessage() . "</strong></p><hr />"; exit( $error ); }; $aParams = array( 'driver' => 'mysql', 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname' ); $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { $dbh = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ] ); } catch( PDOException $e ) { $PDOFatalError( $e ); } // Напишем строку SQL-запроса к базе данных $sql = "SHOW TABLES"; // Обратимся к базе данных, сразу же обрабатывая результат запроса. // Чтобы не сильно нагружать сценарий для такого простого примера, // введем ограничение на 10 записей максимум $i = 0; foreach( $dbh->query( $sql ) as $row ) { print "<pre>"; print_r( $row ); print "</pre>"; if ( $i === 10 ) { break; } ++$i; } ?>
Многие из вас посмотрят на результат запроса с некоторым недоумением, и будут правы. Чтобы результат выглядел более привычно для многих из вас, его нужно представить в виде ассоциативного массива, например. А чтобы это произошло, при подключении к СУБД нужно указать опцию, которая сообщит объекту PDO о том, что мы все результаты запросов хотим видеть, например, как ассоциативные массивы (ну, вроде как результат запроса через функцию mysql_fetch_assoc()). Дополним массив с параметрами подключения.
Помимо озвученного, мы добавим параметр, который позволит использовать постоянные соединения с СУБД.
Постоянные соединения не закрываются при завершении работы скрипта, они кешируются и используются повторно, когда другой скрипт запрашивает соединение с теми же учетными данными. Постоянные соединения позволяют избежать создания новых подключений каждый раз, когда требуется обмен данными с базой, что в результате дает прирост скорости работы таких приложений.
Так говорится на странице официальной документации.
<?php /** * Анонимной функции будет передан в качестве аргумента * объект типа PDOException */ $PDOFatalError = function( PDOException $e ) { $error = "<hr /><p style=\"background-color:red;\">Ошибка выполнения подключения к СУБД: <strong>" . $e->getCode() . "</strong>. Ошибка: <strong>" . $e->getMessage() . "</strong></p><hr />"; exit( $error ); }; $aParams = array( 'driver' => 'mysql', 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname', 'charset' => 'utf8', 'params' => array( // Дополнительные параметры подключения PDO::ATTR_PERSISTENT => true, // Использовать постоянные подключения ) ); $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { // Последним аргументом передаётся массив с дополнительными параметрами $dbh = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ], $aParams[ 'params' ] ); // Устанавливаем режим обработки ошибок, // используя для этого метод setAttribute() объекта PDO $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Устанавливаем режим выборки по умолчанию для объекта запроса, // используя для этого метод setAttribute() объекта PDO $dbh->setAttribute( PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC ); } catch( PDOException $e ) { $PDOFatalError( $e ); } // Напишем строку SQL-запроса к базе данных $sql = "SHOW TABLES"; // Обратимся к базе данных, сразу же обрабатывая результат запроса. // Чтобы не сильно нагружать сценарий для такого простого примера, // введем ограничение на 10 записей максимум $i = 0; foreach( $dbh->query( $sql ) as $row ) { print "<pre>"; print_r( $row ); print "</pre>"; if ( $i === 10 ) { break; } ++$i; } ?>
При желании можно получать результат запроса в виде объекта, где имена столбцов таблицы будут являться именами свойств объекта. Для этого в месте установки режима выборки по умолчанию нужно вместо константы PDO::FETCH_ASSOC указать константу PDO::FETCH_OBJ.
Кто-то из вас спросит, и будет, в общем-то, прав: «а почему мы обработчик ошибок сделали свой, создав анонимную функцию, а вот подключаемся к базе напрямую из сценария?». Да! Давайте и это изменим! Но функцию-обработчик ошибок сделаем обычной.
<?php /** * Функции будет передан в качестве аргумента * объект типа PDOException */ function PDOFatalError( PDOException $e ) { $error = "<hr /><p style=\"background-color:red;\">Ошибка выполнения подключения к СУБД: <strong>" . $e->getCode() . "</strong>. Ошибка: <strong>" . $e->getMessage() . "</strong></p><hr />"; exit( $error ); } /** * Анонимная функция для установки соединения с СУБД * Функции через массив можно дополнительно передавать свои параметры */ $Dbh = function( array $array = array() ) { $aParams = array( 'driver' => 'mysql', 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname', 'charset' => 'utf8', 'params' => array( // Дополнительные параметры подключения PDO::ATTR_PERSISTENT => true, // Использовать постоянные подключения ) ); // Можно и переопределить некоторые из параметров при вызове функции $aParams = $array += $aParams; // Строка с параметрами подключения к СУБД $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { // Последним аргументом передаётся массив с дополнительными параметрами $dbh = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ], $aParams[ 'params' ] ); // Устанавливаем режим обработки ошибок, // используя для этого метод setAttribute() объекта PDO $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Устанавливаем режим выборки по умолчанию для объекта запроса, // используя для этого метод setAttribute() объекта PDO $dbh->setAttribute( PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC ); } catch( PDOException $e ) { PDOFatalError( $e ); } return $dbh; }; // Напишем строку SQL-запроса к базе данных $sql = "SHOW TABLES"; // Создаем подключение к СУБД $dbh = $Dbh(); // Обратимся к базе данных, сразу же обрабатывая результат запроса. // Чтобы не сильно нагружать сценарий для такого простого примера, // введем ограничение на 10 записей максимум $i = 0; foreach( $dbh->query( $sql ) as $row ) { print "<pre>"; print_r( $row ); print "</pre>"; if ( $i === 10 ) { break; } ++$i; } ?>
А теперь смотрите! Передаем функции при установлении соединения с СУБД неверный пароль.
<?php /** * Функции будет передан в качестве аргумента * объект типа PDOException */ function PDOFatalError( PDOException $e ) { $error = "<hr /><p style=\"background-color:red;\">Ошибка выполнения подключения к СУБД: <strong>" . $e->getCode() . "</strong>. Ошибка: <strong>" . $e->getMessage() . "</strong></p><hr />"; exit( $error ); } /** * Анонимная функция для установки соединения с СУБД * Функции через массив можно дополнительно передавать свои параметры */ $Dbh = function( array $array = array() ) { $aParams = array( 'driver' => 'mysql', 'host' => 'yourhost', 'user' => 'dbusername', 'password' => 'dbuserpassword', 'dbname' => 'dbname', 'charset' => 'utf8', 'params' => array( // Дополнительные параметры подключения PDO::ATTR_PERSISTENT => true, // Использовать постоянные подключения ) ); // Можно и переопределить некоторые из параметров при вызове функции $aParams = $array += $aParams; // Строка с параметрами подключения к СУБД $str = $aParams[ 'driver' ] . ':host='. $aParams[ 'host' ] . ';dbname=' .$aParams[ 'dbname' ] . ';charset=' . $aParams[ 'charset' ]; // Специальная конструкция для «отлавливания» ошибок try { // Последним аргументом передаётся массив с дополнительными параметрами $dbh = new PDO( $str, $aParams[ 'user' ], $aParams[ 'password' ], $aParams[ 'params' ] ); // Устанавливаем режим обработки ошибок, // используя для этого метод setAttribute() объекта PDO $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Устанавливаем режим выборки по умолчанию для объекта запроса, // используя для этого метод setAttribute() объекта PDO $dbh->setAttribute( PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC ); } catch( PDOException $e ) { PDOFatalError( $e ); } return $dbh; }; // Напишем строку SQL-запроса к базе данных $sql = "SHOW TABLES"; // Создаем подключение к СУБД $dbh = $Dbh( array( 'password' => 'wrong_password' ) ); // Обратимся к базе данных, сразу же обрабатывая результат запроса. // Чтобы не сильно нагружать сценарий для такого простого примера, // введем ограничение на 10 записей максимум $i = 0; foreach( $dbh->query( $sql ) as $row ) { print "<pre>"; print_r( $row ); print "</pre>"; if ( $i === 10 ) { break; } ++$i; } ?>
На экране видим сообщение об ошибке.
Пользуйтесь! Конечно же, правильнее было бы поместить подключение к СУБД не внутрь анонимной функции, а внутрь своего объекта класса — наследника PDO. Но это уже совсем другая история...
P.S. Конечно же, этот код будет работать не на всез версиях PHP. Какая версия вам нужна? Оставлю вам это в качестве домашнего задания =)
Описанный скрипт доступен для скачивания по ссылке.