Как правильно настроить соединение PDO

Время от времени я вижу вопросы о подключении к базе данных.
Большинство ответов – это не то, как я это делаю, или я просто не могу правильно ответить. Так или иначе; Я никогда не думал об этом, потому что способ, которым я это делаю, работает для меня.

Но вот сумасшедшая мысль; Возможно, я делаю все это неправильно, и если это так; Мне бы очень хотелось знать, как правильно подключиться к базе данных MySQL с помощью PHP и PDO и сделать ее доступной.

Вот как я это делаю:

Во-первых, вот моя файловая структура (урезанная) :

public_html/ * index.php * initialize/ -- load.initialize.php -- configure.php -- sessions.php 

index.php
На самом верху я require('initialize/load.initialize.php'); ,

load.initialize.php

 # site configurations require('configure.php'); # connect to database require('root/somewhere/connect.php'); // this file is placed outside of public_html for better security. # include classes foreach (glob('assets/classes/*.class.php') as $class_filename){ include($class_filename); } # include functions foreach (glob('assets/functions/*.func.php') as $func_filename){ include($func_filename); } # handle sessions require('sessions.php'); - # site configurations require('configure.php'); # connect to database require('root/somewhere/connect.php'); // this file is placed outside of public_html for better security. # include classes foreach (glob('assets/classes/*.class.php') as $class_filename){ include($class_filename); } # include functions foreach (glob('assets/functions/*.func.php') as $func_filename){ include($func_filename); } # handle sessions require('sessions.php'); 

Я знаю, что есть лучший, или более правильный способ включения классов, но не помню, что это было. Не получили времени, чтобы изучить его еще, но я думаю, что это было что-то с autoload . что-то вроде того…

configure.php
Здесь я в основном просто переопределяю некоторые php.ini -properties и выполняю некоторые другие глобальные настройки для сайта

connect.php
Я установил соединение в класс, чтобы другие классы могли расширять этот …

 class connect_pdo { protected $dbh; public function __construct() { try { $db_host = ' '; // hostname $db_name = ' '; // databasename $db_user = ' '; // username $user_pw = ' '; // password $con = new PDO('mysql:host='.$db_host.'; dbname='.$db_name, $db_user, $user_pw); $con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); $con->exec("SET CHARACTER SET utf8"); // return all sql requests as UTF-8 } catch (PDOException $err) { echo "harmless error message if the connection fails"; $err->getMessage() . "<br/>"; file_put_contents('PDOErrors.txt',$err, FILE_APPEND); // write some details to an error-log outside public_html die(); // terminate connection } } public function dbh() { return $this->dbh; } } # put database handler into a var for easier access $con = new connect_pdo(); $con = $con->dbh(); // 

Здесь я действительно верю, что есть место для массового улучшения, так как я недавно начал изучать ООП и использовал PDO вместо mysql.
Поэтому я только что последовал за несколькими учебниками для начинающих и опробовал разные вещи …

sessions.php
Помимо обработки обычных сеансов, я также инициализирую некоторые классы в сеансе следующим образом:

 if (!isset($_SESSION['sqlQuery'])){ session_start(); $_SESSION['sqlQuery'] = new sqlQuery(); } 

Таким образом, этот класс доступен повсеместно. Это может быть не очень хорошая практика (?) …
Во всяком случае, это то, что этот подход позволяет мне делать везде:

 echo $_SESSION['sqlQuery']->getAreaName('county',9); // outputs: Aust-Agder (the county name with that id in the database) 

Внутри моего класса sqlQuery , который extends мой класс connect_pdo , у меня есть открытая функция getAreaName которая обрабатывает запрос в моей базе данных.
Думаю, довольно аккуратный.

Работает как шарм
Так вот в основном, как я это делаю.
Кроме того, всякий раз, когда мне нужно что-то извлекать из моего БД из класса, я просто делаю что-то похожее на это:

 $id = 123; $sql = 'SELECT whatever FROM MyTable WHERE id = :id'; $qry = $con->prepare($sql); $qry -> bindParam(':id', $id, PDO::PARAM_INT); $qry -> execute(); $get = $qry->fetch(PDO::FETCH_ASSOC); 

Поскольку я вставляю соединение в переменную внутри connect_pdo.php , я просто ссылаюсь на нее, и мне хорошо идти. Оно работает. Я получаю ожидаемые результаты …

Но независимо от этого; Я был бы очень признателен, если бы вы, ребята, могли сказать мне, если я уйду отсюда. Вместо этого я должен был бы изменить области, которые я мог или должен изменить для улучшения и т. Д. …

Я очень хочу учиться …

Цель

Как я вижу, ваша цель в этом случае двоякая:

  • создавать и поддерживать одно / многоразовое соединение для каждой базы данных
  • убедитесь, что соединение настроено правильно

Решение

Я бы рекомендовал использовать как анонимную функцию, так и заводскую схему для работы с PDO-соединением. Его использование будет выглядеть так:

 $provider = function() { $instance = new PDO('mysql:......;charset=utf8', 'username', 'password'); $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $instance; }; $factory = new StructureFactory( $provider ); 

Затем в другом файле или ниже в том же файле:

 $something = $factory->create('Something'); $foobar = $factory->create('Foobar'); 

Сама фабрика должна выглядеть примерно так:

 class StructureFactory { protected $provider = null; protected $connection = null; public function __construct( callable $provider ) { $this->provider = $provider; } public function create( $name) { if ( $this->connection === null ) { $this->connection = call_user_func( $this->provider ); } return new $name( $this->connection ); } } 

Таким образом, вы можете иметь централизованную структуру, которая гарантирует, что соединение создается только тогда, когда это необходимо. Это также облегчило бы процесс модульного тестирования и обслуживания.

Поставщик в этом случае будет найден где-то на этапе начальной загрузки. Этот подход также даст четкое местоположение, где можно определить конфигурацию, которую вы используете для подключения к БД.

Имейте в виду, что это чрезвычайно упрощенный пример . Вам также может понравиться смотреть два следующих видео:

  • Глобальное государство и синглтоны
  • Не смотрите на вещи!

Кроме того, я настоятельно рекомендую прочитать правильный учебник об использовании PDO (есть журнал плохого учебника онлайн).

Я бы предложил не использовать $_SESSION для доступа к вашему соединению с БД глобально.

Вы можете сделать одну из нескольких вещей (в порядке худших для лучших практик):

  • Доступ к $dbh с использованием global $dbh внутри ваших функций и классов
  • Используйте одноэлементный реестр и доступ к нему глобально, например:

     $registry = MyRegistry::getInstance(); $dbh = $registry->getDbh(); 
  • Внесите обработчик базы данных в нужные ему классы:

     class MyClass { public function __construct($dbh) { /* ... */ } } 

Я бы очень рекомендовал последний. Он известен как инъекция зависимостей (DI), инверсия контроля (IoC) или просто принцип Голливуда (не называйте нас, мы вам позвоним).

Однако он немного более продвинутый и требует больше «проводки» без рамки. Таким образом, если инъекция зависимостей слишком сложна для вас, используйте реестр singleton вместо совокупности глобальных переменных.

Недавно я пришел к аналогичному ответу / вопросу самостоятельно. Это то, что я сделал, в случае, если кто-то заинтересован:

 <?php namespace Library; // Wrapper for \PDO. It only creates the rather expensive instance when needed. // Use it exactly as you'd use the normal PDO object, except for the creation. // In that case simply do "new \Library\PDO($args);" with the normal args class PDO { // The actual instance of PDO private $db; public function __construct() { $this->args = func_get_args(); } public function __call($method, $args) { if (empty($this->db)) { $Ref = new \ReflectionClass('\PDO'); $this->db = $Ref->newInstanceArgs($this->args); } return call_user_func_array(array($this->db, $method), $args); } } 

Для его вызова вам нужно только изменить эту строку:

 $DB = new \Library\PDO(/* normal arguments */); 

И тип-намек, если вы используете его (\ Library \ PDO $ DB).

Это действительно похоже на принятый ответ и ваш; однако он имеет значительное преимущество. Рассмотрим этот код:

 $DB = new \Library\PDO( /* args */ ); $STH = $DB->prepare("SELECT * FROM users WHERE user = ?"); $STH->execute(array(25)); $User = $STH->fetch(); 

Хотя он может выглядеть как обычный PDO (он изменяется только этим \Library\ only), он фактически не инициализирует объект, пока вы не вызовете первый метод, в зависимости от того, что это такое. Это делает его более оптимизированным, поскольку создание объекта PDO немного дорого. Это прозрачный класс, или то, что он называется Призрак , форма Lazy Loading . Вы можете обрабатывать $ DB как обычный экземпляр PDO, передавать его, выполнять те же операции и т. Д.

 $dsn = 'mysql:host=your_host_name;dbname=your_db_name_here'; // define host name and database name $username = 'you'; // define the username $pwd='your_password'; // password try { $db = new PDO($dsn, $username, $pwd); } catch (PDOException $e) { $error_message = $e->getMessage(); echo "this is displayed because an error was found"; exit(); } 

или читайте на http://ask.hcig.co.za/?p=179