Jak prawidłowo skonfigurować połączenie PDO

Od czasu do czasu widzę pytania dotyczące łączenia się z bazą danych.
Większość odpowiedzi nie jest tak, jak to robię, lub mogę po prostu nie uzyskać odpowiedzi poprawnie. W każdym razie, nigdy o tym nie myślałem, bo sposób, w jaki to robię, działa na mnie.

Ale tu jest szalona myśl; może robię to wszystko źle, a jeśli tak, naprawdę chciałbym wiedzieć, jak poprawnie połączyć się z bazą danych MySQL za pomocą PHP i PDO i ułatwić jej dostęp.

Oto jak sobie radzę it:

Po pierwsze, oto moja struktura plików (rozebrana):

public_html/

* index.php  

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

Indeks.php
Na samej górze mam require('initialize/load.initialize.php');.

Ładuj.inicjalizuj.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');

wiem, że jest lepszy, lub bardziej poprawny sposób na włączenie zajęć, ale nie pamiętam, co to było. Nie miałem jeszcze czasu, żeby się temu przyjrzeć, ale myślę, że to było coś z autoload. coś jak to...

Konfiguracja.php
Tutaj po prostu nadpisuję niektóre php.ini - właściwości i zrobić jakąś inną globalną konfigurację dla strony

Połącz się.php
Umieściłem połączenie na klasie, aby inne klasy mogły rozszerzyć tę...

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();
//

tutaj uważam, że jest miejsce na ogromną poprawę, ponieważ niedawno zacząłem uczyć się OOP i używać PDO zamiast mysql.
Więc właśnie podążałem za kilka samouczków dla początkujących i wypróbowanych różnych rzeczy...

Sesje.php
Oprócz obsługi zwykłych sesji, inicjalizuję również niektóre klasy w sesję taką jak ta:

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

W ten sposób ta klasa jest dostępna wszędzie. To może nie być dobra praktyka(?)...
W każdym razie to właśnie to podejście pozwala mi robić zewsząd: {]}

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

Inside my sqlQuery-klasa , która extends moja connect_pdo-klasa , mam publiczna funkcja o nazwie getAreaName, która obsługuje żądanie do mojej bazy danych.
Myślę, że całkiem nieźle.

Działa jak urok
Więc tak to robię.
Poza tym, ilekroć muszę pobrać coś z mojego DB spoza klasy, po prostu robię coś podobnego do tego: {]}

$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);

Ponieważ umieściłem połączenie w zmiennej wewnątrz connect_pdo.php , po prostu mam do niego odniesienie i jestem gotowy. To działa. I get my expected wyniki...

Ale bez względu na to, byłbym naprawdę wdzięczny, jeśli moglibyście mi powiedzieć, czy jestem daleko stąd. Co powinienem zrobić zamiast tego, obszary, które mógłbym lub powinienem zmienić w celu poprawy itp...

Jestem chętny do nauki...
Author: manian, 2012-07-07

4 answers

Cel

Jak widzę, Twój cel w tym przypadku jest dwojaki:

  • tworzenie i utrzymywanie pojedynczego/wielokrotnego użytku połączenia dla bazy danych
  • upewnij się, że połączenie zostało poprawnie skonfigurowane

Rozwiązanie

Zalecałbym użycie zarówno funkcji anonimowej, jak i wzorca fabrycznego do radzenia sobie z połączeniem PDO. Jego użycie wygląda tak:

$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 );

Następnie w innym pliku lub niżej w tym samym pliku:

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

Fabryka samo powinno wyglądać mniej więcej tak:

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 );
    }

}

W ten sposób uzyskasz scentralizowaną strukturę, która zapewnia, że połączenie jest tworzone tylko wtedy, gdy jest to wymagane. Znacznie ułatwiłoby to również proces testowania i konserwacji urządzeń.

Dostawca w tym przypadku byłby znaleziony gdzieś na etapie bootstrap. Takie podejście daje również jasne miejsce, w którym można zdefiniować konfigurację, której używasz do łączenia się z DB.

Należy pamiętać, że jest to bardzo uproszczony przykład. Możesz również skorzystać z obejrzenia dwóch następujących filmów:

Również zdecydowanie polecam przeczytanie odpowiedniego tutoriala o używaniu PDO (w Internecie jest dziennik złych tutoriali).

 100
Author: tereško,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-27 22:53:25

Sugerowałbym nie używać $_SESSION, aby uzyskać dostęp do połączenia DB globalnie.

Możesz zrobić jedną z kilku rzeczy (w kolejności od najgorszych do najlepszych praktyk):

  • Access $dbh using global $dbh inside of your functions and classes
  • Użyj rejestru singleton i uzyskaj dostęp do niego globalnie, w ten sposób:

    $registry = MyRegistry::getInstance();
    $dbh = $registry->getDbh();
    
  • Wstrzyknąć obsługę bazy danych do klas, które jej potrzebują, w ten sposób:

    class MyClass {
        public function __construct($dbh) { /* ... */ }
    }
    
Gorąco polecam ten ostatni. Jest znany jako dependency injection (DI), inversion of control (IoC), lub po prostu zasada Hollywood (Don 't call us, we' ll call you).

Jest jednak nieco bardziej zaawansowany i wymaga więcej "okablowania" bez ram. Tak więc, jeśli wstrzykiwanie zależności jest zbyt skomplikowane dla ciebie, użyj rejestru singleton zamiast kilku zmiennych globalnych.

 22
Author: Ian Unruh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-15 09:24:24

Niedawno doszedłem do podobnej odpowiedzi/pytania na własną rękę. To właśnie zrobiłem, na wypadek gdyby ktoś był zainteresowany:

<?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);
    }
  }

Aby go wywołać wystarczy zmodyfikować ten wiersz:

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

I typ-hinting jeśli używasz go do (\Library\PDO $DB).

Jest bardzo podobny zarówno do zaakceptowanej odpowiedzi, jak i Twojej; ma jednak znaczną przewagę. Rozważ ten kod:

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

$STH = $DB->prepare("SELECT * FROM users WHERE user = ?");
$STH->execute(array(25));
$User = $STH->fetch();

Chociaż może wyglądać jak normalne PDO (zmienia się tylko przez to \Library\), to w rzeczywistości nie inicjalizuj obiekt, dopóki nie wywołasz pierwszej metody, niezależnie od tego, która z nich jest. To sprawia, że jest bardziej zoptymalizowany, ponieważ tworzenie obiektu PDO jest nieco kosztowne. Jest to klasa przezroczysta, lub jak to się nazywa Ghost , forma leniwego ładowania . Możesz traktować $DB jako normalną instancję PDO, przekazując ją, wykonując te same operacje itp.

 7
Author: Francisco Presencia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:37
$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();
}

Lub czytaj dalej http://ask.hcig.co.za/?p=179

 0
Author: hi-code,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-29 11:55:36