it-swarm.com.ru

Как правильно настроить соединение 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');

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

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

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

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-class, которая extends my connect_pdo-class, у меня есть открытая функция 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, я просто ссылаюсь на него, и я готов к работе. Оно работает. Я получаю ожидаемые результаты ...

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

Я хочу учиться ...

87
ThomasK

Цель

На мой взгляд, ваша цель в этом случае двоякая: 

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

Решение

Я бы рекомендовал использовать как анонимную функцию, так и фабричный шаблон для работы с 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 (в Интернете есть журнал плохих учебников).

102
tereško

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

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

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

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

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

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

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

22
Ian Unruh

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

<?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\), он на самом деле не инициализирует объект, пока вы не вызовете первый метод, какой бы он ни был. Это делает его более оптимизированным, поскольку создание объекта PDO немного дороже. Это прозрачный класс, или то, что он называется Ghost , форма Ленивая загрузка . Вы можете рассматривать $ DB как обычный экземпляр PDO, передавать его, выполнять те же операции и т.д.

7
Francisco Presencia
$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

0
hi-code