PHP : Initiation à la classe PDO

pdo1

La classe PDO va vous permettre d’accéder et de communiquer directement et de façon uniforme à n’importe quelle base de données parmi celles supportées (MySQL, SQLite, PostgreSQL, Oracle…) en vous aidant de fonctionnalités avancées. Nous allons découvrir dans cet article comment créer les habituelles requêtes SELECT, UPDATE, INSERT et les quelques nouveautés que propose cet objet, notamment les notions de préparation des requêtes et de transaction.

Les pré-requis

PDO à été intégré à PHP à partir de la version 5.1 (Ce fut d’ailleurs la raison principale de la sortie de cette version mineure). Si vous testez sur un logiciel de simulation comme WAMP5 ou EasyPHP assurez-vous que la version de PHP soit au moins à 5.1. Et si vous êtes directement en ligne sur un hébergeur mutualisé, vérifiez avec votre hébergeur la version de PHP.
Il vous faudra aussi quelques notions de programmation objet (mais rien de très compliqué!).

Comment initialiser votre objet PDO ?

Nous travaillerons avec une base de données MySQL.
Pour commencer nous allons initialiser notre objet PDO :

$DB = new PDO('mysql :host=localhost ;dbname=bddexemple', 'user', 'passe');

Un peu comme la fonction mysql_connect nous renseignons les identifiants pour se connecter à la base de données.
En premier paramètre : l’adresse de l’hôte (sur WAMP5 ce sera localhost), ainsi que le nom de la base de données (ici bddexemple).
En second paramètre : le nom d’utilisateur de la base de données (ici user).
En troisième paramètre : le mot de passe de la base de données (ici passe).
Pour vérifier que votre objet a bien été initialisé, nous pouvons tenter de récupérer les erreurs possibles (si les identifiants sont incorrects par exemple) avec une Exception (try et catch) :

 
try {
$DB = new PDO('mysql :host=localhost ;dbname=bddexemple', 'user', 'passe') ;
}
catch(PDOException $e) {
echo "Impossible de se connecter!";
}

Les requêtes SQL

Maintenant que notre objet est en place, nous allons voir quelques unes des différentes méthodes qu’il est possible d’exécuter.

Faire un « SELECT » de données

Peu différent de la fonction mysql_query, pour aller chercher des données nous utiliserons la méthode query :

$req = $DB->query('SELECT pseudo, mail FROM comments');

Et pour aller chercher le résultat associé à cette requête on utilisera la méthode fetch dans une boucle while, (un peu comme la fonction mysql_fetch_array) :

$req = $DB->query('SELECT pseudo, mail FROM comments');
while($d = $req->fetch()) {
echo $d['pseudo'];
}

Faire un « UPDATE » de données

La méhode queryest utilisée habituellement dans le cas d’une sélection de données, pour les autres types de requêtes on utilisera la méthode exec comme ci-dessous:

$res = $DB->exec("UPDATE comments SET name = 'Nicolas'");

De plus, la méthode exec retournera le nombre d’élément mis à jour.

Faire un « INSERT » de données

Pour insérer des données dans une table c’est un peu plus compliqué que d’habitude, il faudra passer par deux étapes avant d’exécuter la requête finale.
Premièrement nous déclarer les données à insérer.
Ces données devront être stockées dans un tableau de la façon suivante :

/* 1ère étape : les données */
$d = array("Nicolas", "Bonjour!");

Dans notre exemple nous allons tenter d’insérer une ligne d’enregistrement avec le nom d’utilisateur (ici ‘Nicolas’) et le contenu du commentaire (ici ‘Bonjour!’).
Ensuite en seconde étape nous devons préparer la requête grâce à la méthode prepare :

/* 2ème étape : préparer la requête */
$req = $DB->prepare('INSERT INTO comments (name, content) VALUE (?, ?)');

Comme vous pouvez le voir il y a 2 points d’interrogation, et c’est normal, ce sont des marqueurs.
Le premier point d’interrogation correspond à la première valeur de notre tableau $d.
Le second point d’interrogation correspond à la seconde valeur de notre tableau $d.
Et ainsi de suite si l’on a plus de 2 champs…
La méthode prepare optimise les performances de votre application et aide à prévenir les attaques par injection SQL en éliminant le besoin de protéger les paramètres manuellement.
Il ne nous reste plus qu’à exécuter notre requête avec la méthode execute :

/* 1ère étape : les données */
$d = array("Nicolas", "Bonjour!");
/* 2ème étape : préparer la requête */
$req = $DB->prepare('INSERT INTO comments (name, content) VALUE (?, ?)')
/* On exécute la requête */
$req->execute($d);

Si jamais vous devez faire une requête SQL du type INSERT avec une vingtaine de champs, cela peut-être assez pénible et trompeur d’utiliser cette méthode de préparation de requête avec une vingtaine de points d’interrogation, c’est pourquoi il existe une autre façon de faire, nous pouvons préparer la requête avec des paramètres nommés. Voyez plutôt l’exemple ci-dessous :

/* 1ère étape : les données */
$d = array(
'nom' => "Nicolas",
'content' => "Bonjour, voici mon commentaire"
);
/* 2ème étape : préparer la requête */
$req = $DB->prepare('INSERT INTO comments (name, content) VALUE (:nom, :content)');
/* On exécute la requête */
$req->execute($d);

Petite astuce : si on souhaite récupérer l’identifiant de la dernière ligne insérée on peut utiliser la méthode lastInsertId :

$lastId = $req->lastInsertId();

Et pour insérer plusieurs lignes d’enregistrements dans notre table, on utilisera un tableau de données multidimensionnelles :

/* 1ère étape : tableau de donnée multidimensionnelle */
$d = array(
array(
'nom' => "Nicolas",
'content' => "Bonjour, voici mon commentaire"
),
array(
'nom' => "Patrick",
'content' => "Salut, ceci est mon commentaire"
)
);
/* 2ème étape : préparer la requête (pas de changement de ce coté là) */
$req = $DB->prepare('INSERT INTO comments (name, content) VALUE (:nom, :content)');
/* Et nous allons parcourir le tableau avec la fonction foreach */
foreach($d as $v) {
$req->execute($v);
}

Notez que dans notre exemple nous avons utilisé une requete type INSERT, mais il est tout à fait possible d’utiliser UPDATE.

Les transactions

Les transactions vous garantissent dans presque 100% des cas d’avoir vos requêtes SQL menées à bien et appliqué à la base de données sans risque, et sans interférence pour les autres connexions. Les transactions sont typiquement implémentées pour appliquer toutes vos modifications en une seule fois.

Pour faire simple, imaginons qu’un consommateur achète un objet de 100€ dans un magasin.
Nous allons mettre à jour la solde de l’acheteur et celle de la caisse du magasin.

$DB->exec('UPDATE consommateurs SET solde = solde - 100 WHERE id = 5');
$DB->exec('UPDATE caisse_magasin SET solde = solde + 100');

Dans notre exemple les deux requêtes doivent s’exécuter sans soucis et ne doivent pas rencontrer de problèmes (dans le cas où le serveur MySQL plante après la première requête par exemple) si l’on ne veut pas se retrouver avec des problèmes dans les soldes de chacuns.
Pour s’en assurer nous allons utiliser les transactions.
Pour mettre une transaction en place nous passerons par quelques étapes très simples :
Dans un premier temps nous allons initialiser la transaction grâce à la méthode beginTransaction.

$DB->beginTransaction();

Pour la suite on déclarera nos requêtes :

$DB->exec('UPDATE consommateurs SET solde = solde - 100 WHERE id = 5');
$DB->exec('UPDATE caisse_magasin SET solde = solde + 100');

Enfin on applique ces deux requêtes avec la méthode commit :

$DB->commit();

Si tout se passe bien alors ces 2 requêtes seront appliquées à la base de données, mais en cas d’erreur on va la traiter et annuler les requêtes précédentes avec la méthode rollback.

$DB->rollback();

Ce qui avec le système des exceptions donne cela au final :

try
{
// Début de la transaction	
$DB->beginTransaction();
// Déclaration des deux requêtes
$DB->exec('UPDATE consommateurs SET solde = solde - 100 WHERE id = 5');
$DB->exec('UPDATE caisse_magasin SET solde = solde + 100');
// On exécute les requêtes 
$DB->commit();
echo "Tout s'est bien déroulé";
}
catch(Exception $e)
{
// En cas d'erreur on annule la transaction
$pdo->rollback();
echo "Il y a eu un problème";
}

Voilà donc à quoi ressemble une transaction complète, cela permet d’être sûr que tout s’est bien passé dans notre programme. Les transactions sont surtout utilisées dans des bases de données nécessitant une fiabilité à toute épreuve (la finance, santé…).

Nicolas Verhoye

Développeur Magento, Freelance

  1. Robin dit :

    Clair, concis, pertinent -> bookmark

  2. DevPHP dit :

    Je vois que tu utilise exclusivement des requêtes $DB->exec, n’est-il pas possible de faire des requêtes préparer ?

  3. Nicolas Verhoye dit :

    J’utilise exclusivement des requêtes $DB->exec dans l’exemple des transactions pour éviter de trop surcharger et pour simplifier au maximum. Mais il est tout à fait possible d’utiliser des requêtes $DB->prepare oui! Bonne journée

  4. jules dit :

    Tout d’abord bonsoir nicolas j’essaye d’effectuer ,un minichat dans mon site l’insertion s’effectue bien quant à la recupération des donnée pour affichage dans à l’écran j’ai ce messge d’erreur Call to a member function fetchall() on a non-object in C:xampphtdocsmyshopstore_scriptminichat.php on line 106 la table comporte 3 champs id ,pseudo et le message cependant je voudrai afficher seulement le pseudo et le message

  5. imen dit :

    bonjour,
    je veux faire une insertion dans une base de données Mysql que j’ai déjà préparé.
    je veux faire la connexion, l’insertion, et la recherche sur cette base en utilisant l’extension PDO.
    Merci de me répondre.

    1. Matthieu dit :

      Eh ben, la politesse n’est pas votre fort Imen :-)

  6. FX dit :

    Je n’ai rien compris mais félicitation pour ton travail Nico !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *