web-dev-qa-db-fra.com

Comment configurer correctement une connexion PDO

De temps en temps, je vois des questions concernant la connexion à la base de données.
La plupart des réponses ne sont pas comme je le fais, ou je pourrais ne pas obtenir les réponses correctement. En tous cas; Je n'y ai jamais pensé parce que je le fais comme ça.

Mais voici une pensée folle; Peut-être que je fais tout faux, et si c'est le cas; J'aimerais vraiment savoir comment me connecter correctement à une base de données MySQL en utilisant PHP et PDO et la rendre facilement accessible.

Voici comment je le fais:

Tout d’abord, voici ma structure de fichiers (allégée):

public_html/

* index.php  

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

index.php
Tout en haut, j'ai 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');

Je sais qu'il y a une manière meilleure, ou plus correcte, d'inclure des cours, mais je ne me souviens plus de quoi il s'agissait. Je n'ai pas encore eu le temps d'examiner la question, mais je pense que c'était quelque chose avec autoload. quelque chose comme ca...

configure.php
Ici, en gros, je viens de remplacer certaines propriétés php.ini et de faire une autre configuration globale pour le site.

connect.php
J'ai mis la connexion sur une classe afin que les autres classes puissent étend celle-ci ...

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

Je pense que des améliorations considérables sont possibles depuis que j'ai récemment commencé à apprendre la POO et à utiliser PDO au lieu de mysql.
Je viens donc de suivre quelques tutoriels pour débutants et d’essayer différentes choses ...

sessions.php
Outre le traitement des sessions régulières, j'initialise également certaines classes dans une session comme celle-ci: 

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

De cette façon, cette classe est disponible partout. Cela pourrait ne pas être une bonne pratique (?) ...
En tout cas, voici ce que cette approche me permet de faire de partout:

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

Dans ma sqlQuery-class, qui extends mon connect_pdo-class, j'ai une fonction publique appelée getAreaName qui gère la demande à ma base de données.
Assez chouette je pense.

Fonctionne comme un charme
C'est donc comme ça que je le fais.
En outre, chaque fois que je dois extraire quelque chose de ma base de données hors d'une classe, je fais simplement quelque chose de similaire à ceci:

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

Depuis que j'ai mis la connexion dans une variable à l'intérieur de connect_pdo.php, il me suffit de s'y référer et je suis prêt à partir. Ça marche. Je reçois mes résultats escomptés ...

Mais indépendamment de cela; J'apprécierais vraiment si vous pouviez me dire si je suis loin d'ici. Ce que je devrais faire à la place, les domaines que je pourrais ou devrais changer pour l’amélioration, etc. 

J'ai hâte d'apprendre ...

87
ThomasK

Le but

À mon avis, votre objectif dans cette affaire est double: 

  • créer et maintenir une connexion unique/réutilisable par base de données
  • assurez-vous que la connexion a été configurée correctement

Solution

Je recommanderais d'utiliser à la fois une fonction anonyme et un modèle d'usine pour traiter la connexion PDO. Son utilisation ressemblerait à ceci:

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

Puis dans un fichier différent ou plus bas dans le même fichier:

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

L'usine elle-même devrait ressembler à ceci:

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

}

De cette façon, vous disposeriez d'une structure centralisée, qui garantit que la connexion est créée uniquement lorsque cela est nécessaire. Cela faciliterait également le processus de test unitaire et de maintenance.

Le fournisseur dans ce cas se trouverait quelque part au stade du bootstrap. Cette approche donnerait également un emplacement clair pour définir la configuration, que vous utiliserez pour vous connecter à la base de données.

Gardez à l'esprit qu'il s'agit d'un exemple extrêmement simplifié. Vous pouvez également bénéficier des vidéos suivantes:

De plus, je vous recommande fortement de lire un tutoriel approprié à propos de l'utilisation de PDO (il existe un journal de mauvais tutoriel en ligne).

102
tereško

Je suggérerais de ne pas utiliser $_SESSION pour accéder à votre connexion à la base de données de manière globale.

Vous pouvez faire l'une des choses suivantes (dans l'ordre des du moins au meilleur pratiques):

  • Accédez à $dbh en utilisant global $dbh dans vos fonctions et classes.
  • Utilisez un registre singleton et accédez-y globalement, comme ceci:

    $registry = MyRegistry::getInstance();
    $dbh = $registry->getDbh();
    
  • Injectez le gestionnaire de base de données dans les classes qui en ont besoin, comme ceci:

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

Je recommande fortement le dernier. C'est ce qu'on appelle l'injection de dépendance (DI), l'inversion de contrôle (IoC), ou simplement le principe d'Hollywood (ne nous appelez pas, nous vous appellerons).

Cependant, il est un peu plus avancé et nécessite plus de "câblage" sans cadre. Donc, si l'injection de dépendance est trop compliquée pour vous, utilisez un registre singleton au lieu d'un groupe de variables globales.

22
Ian Unruh

Je suis récemment venu à une réponse/question similaire sur mon propre. Voici ce que j'ai fait, au cas où quelqu'un serait intéressé:

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

Pour l'appeler, il suffit de modifier cette ligne:

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

Et l'indication de type si vous l'utilisez pour (\ Library\PDO $ DB).

C'est très semblable à la fois à la réponse acceptée et à la vôtre. Cependant, il a un avantage notable. Considérons ce code:

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

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

Bien que cela puisse ressembler à un PDO normal (il ne change que par le \Library\ uniquement), il n'initialise en fait l'objet que lorsque vous appelez la première méthode, quelle qu'elle soit. Cela le rend plus optimisé, car la création d'objet PDO est légèrement coûteuse. C'est une classe transparente, ou ce qu'on appelle un Ghost , une forme de Lazy Loading . Vous pouvez traiter la $ DB comme une instance PDO normale, la transmettre, effectuer les mêmes opérations, etc.

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

ou lire sur http://ask.hcig.co.za/?p=179

0
hi-code