Мой сайт — моя визитная карточка

Подключение к базе данных через PDO

Для того, чтобы подключиться к нашей СУБД, как и в случае с использованием встроенных функций 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. Какая версия вам нужна? Оставлю вам это в качестве домашнего задания =)

Описанный скрипт доступен для скачивания по ссылке.

Я разместил эту статью: 28.05.2019
Количество просмотров: 157
Яндекс.Метрика