méthodes pdo. Pourquoi devriez-vous utiliser PDO pour accéder aux bases de données ? Traitement des résultats, méthodes FETCH et FETCHALL

Terme AOP est une abréviation du concept Objets de données PHP. Comme son nom l'indique, cette technologie vous permet de travailler avec le contenu d'une base de données via des objets.

Pourquoi pas myqli ou mysql ?

Le plus souvent, en ce qui concerne les nouvelles technologies, la question se pose de leurs avantages par rapport aux bons outils anciens et éprouvés, ainsi que du transfert vers eux des projets actuels et anciens.

PDO Orientation Objet

PHP Il se développe très activement et s'efforce de devenir l'un des meilleurs outils pour le développement rapide d'applications Web, tant au niveau de masse qu'au niveau de l'entreprise.

Parler de PHP, nous voulons dire orienté objet moderne PHP, vous permettant d'écrire du code universel pratique pour les tests et la réutilisation.

Usage AOP vous permet de déplacer le travail de base de données vers un niveau orienté objet et d'améliorer la portabilité du code. En fait, l'utilisation AOP pas aussi difficile qu'on pourrait le penser.

Abstraction

Imaginons que nous développions une application depuis longtemps en utilisant MySQL. Et puis, à un moment donné, il devient nécessaire de remplacer MySQL sur PostgreSQL.

Au minimum, nous devrons remplacer tous les appels mysqli_connect() (mysql_connect()) sur pg_connect() et, par analogie, d'autres fonctions utilisées pour interroger et traiter les données.

En utilisant AOP, nous nous limiterons à modifier quelques paramètres dans les fichiers de configuration.

Liaison de paramètres

L'utilisation de paramètres liés offre une plus grande flexibilité dans la conception des requêtes et améliore la protection contre SQL injections.

Recevoir des données en tant qu'objets

Ceux qui utilisent déjà ORM(cartographie objet-relationnel - mappage objet-relationnel des données), par exemple, Doctrine, connaissez la commodité de représenter les données des tables de base de données sous forme d'objets. AOP permet de recevoir des données sous forme d'objets et sans utiliser ORM.

L'extension mysql n'est plus supportée

Prise en charge des extensions mysql définitivement retiré du nouveau PHP7. Si vous envisagez de migrer le projet vers une nouvelle version PHP, vous devriez utiliser au moins mysqli maintenant. Bien sûr, il vaut mieux commencer à utiliser AOP si vous ne l'avez pas déjà fait.

Il me semble que ces raisons suffisent à faire pencher la balance en faveur de l'utilisation AOP. De plus, vous n’avez rien à installer de plus.

Vérification de la présence de PDO dans le système

Versions PHP5.5 et supérieurs, le plus souvent, contiennent déjà une extension pour travailler avec AOP. Pour vérifier, exécutez simplement une simple commande dans la console :

php -je | grep "pdo"

Ouvrons-le maintenant dans n'importe quel navigateur et trouvons les données nécessaires en recherchant par ligne AOP.

Connaître l'AOP

Processus de travail avec AOP pas trop différent du traditionnel. En général, le processus d'utilisation AOP Ressemble à ça:

  1. Connectez-vous à la base de données ;
  2. Si nécessaire, préparez une demande et liez les paramètres ;
  3. Exécution de la demande.

Connexion à la base de données

Pour vous connecter à la base de données, vous devez créer un nouvel objet AOP et transmettez-lui le nom de la source de données, également appelée DSN.

En général, DSN se compose du nom du pilote séparé par deux points d'une chaîne de connexion spécifique à chaque pilote AOP.

Pour MySQL, la connexion se fait ainsi :

$connection = new PDO("mysql:host=localhost;dbname=mydb;charset=utf8", "root", "root");

$connexion = nouveau PDO ( "mysql:host=localhost;dbname=mydb;charset=utf8", "racine" , "racine" ) ;

Dans ce cas, DSN contient le nom du pilote mysql, indication de l'hôte (format possible hôte=HOST_NAME:PORT), nom de la base de données, encodage, nom d'utilisateur MySQL et son mot de passe.

Demandes

Contrairement à mysqli_query(), V AOP il existe deux types de demandes :

  • Renvoyer le résultat ( sélectionner, afficher);
  • Ne renvoie pas de résultat ( insérer, détail et d'autres).

Tout d’abord, considérons la deuxième option.

Exécuter des requêtes

Regardons un exemple d'exécution d'une requête en utilisant l'exemple insérer.

$connection->exec("INSERT INTO utilisateurs VALUES (1, "une valeur"");

$connexion -> exec() ;

Bien entendu, cette requête renvoie le nombre de lignes concernées et vous pouvez le voir comme suit.

$affectedRows = $connection->exec("INSERT INTO users VALUES (1, "somevalue""); echo $affectedRows;

$affectedRows = $connexion -> exec ( "INSÉRER DANS LES VALEURS des utilisateurs (1, "une valeur"") ;

echo $affectedRows ;

Obtenir les résultats d'une requête

En cas d'utilisation mysqli_query(), le code pourrait être le suivant.

$result = mysql_query("SELECT * FROM utilisateurs"); while($row = mysql_fetch_assoc($result)) ( echo $row["id"] . " " . $row["name"]; )

$result = mysql_query ("SELECT * FROM utilisateurs" ) ;

while ($row = mysql_fetch_assoc ($result) ) (

Pour AOP, le code sera plus simple et plus concis.

foreach($connection->query("SELECT * FROM users") as $row) ( echo $row["id"] . " " . $row["name"]; )

foreach ($connection -> requête ("SELECT * FROM utilisateurs") en tant que $row ) (

echo $row [ "id" ] . " " . $ligne["nom"];

Modes d'acquisition de données

Un péché mysqli, AOP vous permet de recevoir des données dans différents modes. Pour déterminer le mode, la classe AOP contient les constantes correspondantes.

  • PDO::FETCH_ASSOC— renvoie un tableau indexé par le nom de la colonne dans la table de la base de données ;
  • PDO : FETCH_NUM— renvoie un tableau indexé par numéro de colonne ;
  • PDO :: FETCH_OBJ- renvoie un objet anonyme avec des noms de propriétés correspondant aux noms de colonnes. Par exemple, $row->id contiendra la valeur de la colonne id.
  • PDO::FETCH_CLASS— renvoie une nouvelle instance de la classe, avec des valeurs de propriété correspondant aux données de la ligne du tableau. Si le paramètre est spécifié PDO::FETCH_CLASSTYPE(Par exemple PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE), le nom de la classe sera déterminé à partir de la valeur de la première colonne.

Note: Ceci n'est pas une liste complète ; toutes les constantes possibles et leurs combinaisons sont disponibles dans la documentation.

Un exemple d'obtention d'un tableau associatif :

$statement = $connection->query("SELECT * FROM utilisateurs"); while($row = $statement->fetch(PDO::FETCH_ASSOC)) ( echo $row["id"] . " " . $row["name"]; )

$instruction = $connexion ->

while ($row = $statement -> fetch (PDO::FETCH_ASSOC) ) (

echo $row [ "id" ] . " " . $ligne["nom"];

Note: Il est recommandé de toujours spécifier le mode d'échantillonnage car le mode PDO::FETCH_BOTH nécessitera deux fois plus de mémoire - en fait, deux tableaux seront créés, associatif et régulier.

Pensez à utiliser le mode d'échantillonnage PDO::FETCH_CLASS. Créons une classe Utilisateur:

class User ( protected $id; protected $name; public function getId() ( return $this->id; ) public function setId($id) ( $this->id = $id; ) public function getName() ( return $this->name; ) fonction publique setName($name) ( $this->name = $name; ) )

Utilisateur de classe

$id protégé ;

$nom protégé ;

fonction publique getId()

return $this -> id ;

fonction publique setId ($id)

$this -> id = $id ;

fonction publique getName()

return $this -> nom ;

fonction publique setName ($nom)

$this -> nom = $nom ;

Sélectionnons maintenant les données et affichons les données à l'aide des méthodes de classe :

$statement = $connection->query("SELECT * FROM utilisateurs"); while($row = $statement->fetch(PDO::FETCH_CLASS, "User")) ( echo $row->getId() . " " . $row->getName(); )

$statement = $connection -> requête ("SELECT * FROM utilisateurs" ) ;

while ($row = $statement -> fetch (PDO::FETCH_CLASS, "Utilisateur") ) (

echo $row -> getId() . " " . $row -> getName () ;

Requêtes préparées et liaison de paramètres

Pour comprendre l'essence et tous les avantages de la liaison de paramètres, vous devez examiner de plus près les mécanismes AOP. En appelant $instruction -> requête() dans le code ci-dessus, AOP préparera une requête, l’exécutera et renverra le résultat.

En appelant $connexion -> préparer() une demande préparée est créée. Les requêtes préparées sont la capacité d'un système de gestion de base de données à recevoir un modèle de requête, à le compiler et à l'exécuter après avoir récupéré les valeurs des variables utilisées dans le modèle. Les moteurs de modèles fonctionnent de la même manière. Intelligent Et Brindille.

En appelant $instruction -> exécuter() les valeurs de substitution sont transférées au modèle de requête et le SGBD exécute la requête. Cette action est similaire à l'appel de la fonction du moteur de modèle rendre().

Un exemple d'utilisation de requêtes préparées dans PHP AOP:

Dans le code ci-dessus, une demande de sélection d'un enregistrement avec un champ est préparée identifiantégale à la valeur qui sera substituée à : identifiant. A ce stade, le SGBD va analyser et compiler la requête, éventuellement en utilisant la mise en cache (selon les paramètres).

Vous devez maintenant passer le paramètre manquant et exécuter la requête :

$id = 5 ; $statement->execute([ ":id" => $id ]);

Avantages de l'utilisation de paramètres liés

Peut-être qu'après avoir examiné le fonctionnement des requêtes préparées et les paramètres associés, les avantages de leur utilisation deviennent évidents.

AOP fournit un moyen pratique d'échapper aux données utilisateur, par exemple, un code comme celui-ci n'est plus nécessaire :

Au lieu de cela, il est désormais conseillé de faire ceci :

Vous pouvez même raccourcir davantage le code en utilisant des paramètres numérotés au lieu de paramètres nommés :

Dans le même temps, l’utilisation de requêtes préparées améliore les performances lors de l’utilisation répétée du même modèle de requête. Un exemple de sélection de cinq utilisateurs aléatoires dans une base de données :

$numberOfUsers = $connection->query("SELECT COUNT(*) FROM users")->fetchColumn(); $utilisateurs = ; $statement = $connection->prepare("SELECT * FROM utilisateurs WHERE id = ? LIMIT 1"); pour ($i = 1; $i<= 5; $i++) { $id = rand(1, $numberOfUsers); $users = $statement->exécuter([$id])->fetch(PDO::FETCH_OBJ); )

$numberOfUsers = $connection -> requête ("SELECT COUNT(*) FROM users" ) -> fetchColumn () ;

$utilisateurs = ;

pour ($i = 1 ; $i<= 5 ; $i ++ ) {

$id = rand (1 , $numberOfUsers ) ;

$users = $statement -> exécuter ([ $id ] ) -> récupérer (PDO::FETCH_OBJ ) ;

Lors de l'appel d'une méthode préparer(), le SGBD analysera et compilera la requête, en utilisant la mise en cache si nécessaire. Plus tard dans le cycle pour, seules les données sont échantillonnées avec le paramètre spécifié. Cette approche vous permet de récupérer les données plus rapidement, réduisant ainsi le temps d'exécution des applications.

Lors de l'obtention du nombre total d'utilisateurs dans la base de données, la méthode a été utilisée récupérerColonne(). Cette méthode récupère la valeur d'une seule colonne et est utile lors de la récupération de valeurs scalaires telles que le nombre, la somme, les valeurs maximales ou minimales.

Valeurs liées et opérateur IN

Souvent, quand on commence à travailler avec AOP, des difficultés surviennent avec l'opérateur DANS. Par exemple, imaginez que l'utilisateur saisisse plusieurs noms séparés par des virgules. L'entrée de l'utilisateur est stockée dans une variable $noms.

Connexion à la base de données est défini lorsqu'une instance de la classe PDO est créée. Peu importe le pilote que vous choisissez d'utiliser ; Vous devrez toujours utiliser la classe PDO. Son constructeur accepte des paramètres pour spécifier la source de la base de données (appelés DSN) et des paramètres facultatifs pour un nom d'utilisateur et un mot de passe.

Connexion à MySQL :

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass);

Si des erreurs de connexion se produisent, une exception sera levée : un objet de la classe PDOException. Vous pouvez l'attraper si vous souhaitez gérer cette situation, ou vous pouvez le laisser au gestionnaire d'exceptions global, qui est défini via set_exception_handler().

Gestion des erreurs de connexion :

essayez ( $dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass); foreach($dbh->query('SELECT * from FOO') as $row) ( print_r($ row); ) $dbh = null; ) catch (PDOException $e) ( die("Erreur ! C'est tout. Nous y sommes... ".$e->getMessage()); )

Attention: Si vous n'attrapez pas l'exception levée par le constructeur PDO, l'action par défaut prise par le moteur Zend est d'arrêter le script et d'afficher un traçage. Cette merde révélera tous vos détails intimes de communication avec la base de données. C'est affichera les détails détaillés de la connexion à la base de données, y compris le nom d'utilisateur et le mot de passe ! C'est à vous d'intercepter cette exception, soit explicitement (via une instruction essayez d'attraper), ou implicitement via set_exception_handler().

Une fois la connexion à la base de données réussie, elle reste active pendant toute la durée de vie de l'instance d'objet PDO. Pour fermer une connexion, vous devez détruire l'objet, en vous assurant que toutes les références restantes à celui-ci sont supprimées - cela peut être fait en attribuant la valeur NULL à la variable qui contient l'objet. Si vous ne le faites pas explicitement, PHP fermera automatiquement la connexion à la fin du script.

Fermeture d'une connexion :

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass); // On fait quelque chose ici : ... // Et maintenant, attention : fin de connexion ! $dbh = nul ;

De nombreuses applications Web bénéficient de la création de connexions persistantes aux serveurs de bases de données. Les connexions persistantes ne sont pas fermées à la fermeture du script, mais sont mises en cache et réutilisées lorsqu'un autre script demande des connexions en utilisant les mêmes informations d'identification de connexion. Un cache de connexion persistant évite la surcharge liée à l'établissement d'une nouvelle connexion chaque fois qu'un script doit communiquer avec la base de données, ce qui accélère l'exécution des applications Web.

Mise en place d'une connexion permanente :

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

Gardez à l'esprit: Si vous souhaitez utiliser une connexion persistante, vous devez définir PDO::ATTR_PERSISTENT dans le tableau d'options du pilote, qui est transmis au constructeur de la classe PDO. En définissant cet attribut via PDO::setAttribute() une fois l'objet instancié, le pilote n'utilisera pas de liens persistants. Et aussi, dans ce cas, vous ne pourrez pas étendre la classe PDOStatement pour certains de vos besoins, c'est-à-dire il ne sera pas possible d'installer : PDO::ATTR_STATEMENT_CLASS

  • Traduction

De nombreux développeurs PHP sont habitués à utiliser les extensions mysql et mysqli pour travailler avec des bases de données. Mais depuis la version 5.1 en PHP, il existe un moyen plus pratique : les objets de données PHP. Cette classe, appelée PDO en abrégé, fournit des méthodes pour travailler avec des objets et des instructions préparées qui amélioreront considérablement votre productivité !

Introduction à l'AOP

"PDO - PHP Data Objects est une couche qui offre un moyen universel de travailler avec plusieurs bases de données."

Cela laisse au développeur le souci des fonctionnalités syntaxiques des différents SGBD, mais rend le processus de commutation entre les plates-formes beaucoup moins pénible. Souvent, cela nécessite simplement de modifier la chaîne de connexion à la base de données.


Cet article est écrit pour les personnes qui utilisent MySQL et MySQLi pour les aider à migrer vers le PDO plus puissant et plus flexible.

Prise en charge du SGBD

Cette extension peut prendre en charge n'importe quel système de gestion de base de données pour lequel un pilote PDO existe. Au moment de la rédaction, les pilotes suivants sont disponibles :
  • PDO_CUBRID (CUBRID)
  • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
  • PDO_FIREBIRD (Firebird/Interbase 6)
  • PDO_IBM (IBM DB2)
  • PDO_INFORMIX (serveur dynamique IBM Informix)
  • PDO_MYSQL (MySQL 3.x/4.x/5.x)
  • PDO_OCI (interface d'appel Oracle)
  • PDO_ODBC (ODBC v3 (IBM DB2, unixODBC et win32 ODBC))
  • PDO_PGSQL (PostgreSQL)
  • PDO_SQLITE (SQLite 3 et SQLite 2)
  • PDO_SQLSRV (Microsoft SQL Server)
  • PDO_4D (4D)
Cependant, ils ne sont pas tous présents sur votre serveur. Vous pouvez voir la liste des pilotes disponibles comme ceci :
print_r(PDO::getAvailableDrivers());

Connexion

Les méthodes de connexion à différents SGBD peuvent différer légèrement. Vous trouverez ci-dessous des exemples de connexion aux plus populaires. Vous remarquerez que les trois premiers ont une syntaxe identique, contrairement à SQLite.
essayez ( # MS SQL Server et Sybase via PDO_DBLIB $DBH = new PDO("mssql:host=$host;dbname=$dbname", $user, $pass); $DBH = new PDO("sybase:host=$host ;dbname=$dbname", $user, $pass); # MySQL via PDO_MYSQL $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); # SQLite $DBH = new PDO("sqlite:my/database/path/database.db"); catch(PDOException $e) ( echo $e->getMessage(); )
Veuillez faire attention au bloc try/catch - cela vaut toujours la peine d'y envelopper toutes vos opérations PDO et d'utiliser le mécanisme d'exception (nous y reviendrons plus tard).

$DBH signifie « descripteur de base de données » et sera utilisé tout au long de l'article.

Vous pouvez fermer n'importe quelle connexion en redéfinissant sa variable sur null.
# ferme la connexion $DBH = null;
Plus d'informations sur les options distinctives des différents SGBD et les méthodes de connexion à ceux-ci peuvent être trouvées sur php.net.

Exceptions et AOP

PDO peut lever des exceptions sur les erreurs, donc tout doit être dans un bloc try/catch. Immédiatement après la création d'une connexion, PDO peut être placé dans l'un des trois modes d'erreur suivants :
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Mais il convient de noter qu’une erreur lors de la tentative de connexion générera toujours une exception.

PDO::ERRMODE_SILENT

C'est le mode par défaut. Vous utiliserez probablement à peu près la même chose pour détecter les erreurs dans les extensions mysql et mysqli. Les deux modes suivants sont plus adaptés à la programmation DRY.

PDO : ERRMODE_WARNING

Ce mode provoquera un avertissement standard et permettra au script de continuer à s'exécuter. Pratique pour le débogage.

PDO::ERRMODE_EXCEPTION

Dans la plupart des situations, ce type de contrôle d’exécution de script est préférable. Il lève une exception, vous permettant de gérer intelligemment les erreurs et de masquer les informations sensibles. Comme par exemple ici :
# connectez-vous à la base de données essayez ( $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ; # Merde ! J'ai tapé DELECT au lieu de SELECT ! $DBH->prepare("DELECT name FROM people")->execute( ) catch(PDOException $e) ( echo "Houston, nous avons des problèmes."; file_put_contents( "PDOErrors" .txt", $e->getMessage(), FILE_APPEND); )
Il y a une erreur de syntaxe dans l'expression SQL qui lèvera une exception. Nous pouvons enregistrer les détails de l’erreur dans un fichier journal et indiquer à l’utilisateur en langage humain que quelque chose s’est produit.

Insérer et mettre à jour

L'insertion de nouvelles données et la mise à jour des données existantes font partie des opérations de base de données les plus courantes. Dans le cas du PDO, ce processus comprend généralement deux étapes. (La section suivante concerne à la fois UPDATE et INSERT)


Un exemple trivial d'insertion de nouvelles données :
# STH signifie "Statement Handle" $STH = $DBH->prepare("INSERT INTO folks (first_name) values ​​​​("Cathy")"); $STH->exécuter();
En fait, vous pouvez faire la même chose avec une seule méthode exec(), mais la méthode en deux étapes offre tous les avantages des instructions préparées. Ils aident à protéger contre les injections SQL, il est donc logique de les utiliser même pour une requête ponctuelle.

Déclarations préparées

L'utilisation d'instructions préparées renforce la protection contre les injections SQL.

Une instruction préparée est une instruction SQL précompilée qui peut être exécutée de manière répétée en envoyant uniquement différents ensembles de données au serveur. Un avantage supplémentaire est qu'il est impossible d'effectuer une injection SQL via les données utilisées dans les espaces réservés.

Vous trouverez ci-dessous trois exemples de déclarations préparées.
# sans espaces réservés - la porte aux injections SQL est ouverte ! $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) valeurs ($name, $addr, $city)"); # espaces réservés sans nom $STH = $DBH->prepare("INSERT INTO folks (nom, adresse, ville) valeurs (?, ?, ?)"); # espaces réservés nommés $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values ​​​​(:name, :addr, :city)");
Le premier exemple est ici uniquement à titre de comparaison et doit être évité. La différence entre les espaces réservés sans nom et nommés réside dans la manière dont vous transmettez les données aux instructions préparées.

Espaces réservés sans nom

# assigne des variables à chaque espace réservé, avec des indices de 1 à 3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $city); # insérer une ligne $name = "Daniel" $addr = "1 Wicked Way"; $ville = « Hauteurs d'Arlington » ; $STH->exécuter(); # insère une autre ligne, avec des données différentes $name = "Steve" $addr = "5 Circle Drive"; $ville = "Schaumbourg" ; $STH->exécuter();
Il y a deux étapes ici. Sur le premier, nous attribuons des variables à tous les espaces réservés (lignes 2 à 4). Ensuite, nous attribuons des valeurs à ces variables et exécutons la requête. Pour envoyer un nouvel ensemble de données, modifiez simplement les valeurs des variables et réexécutez la requête.

Si votre expression SQL comporte de nombreux paramètres, attribuer une variable à chacun est très gênant. Dans de tels cas, vous pouvez stocker les données dans un tableau et les transmettre :
# l'ensemble de données que nous allons insérer $data = array("Cathy", "9 Dark and Twisty Road", "Cardiff"); $STH = $DBH->prepare("INSERT INTO people (nom, adresse, ville) valeurs (?, ?, ?)"); $STH->exécuter($data);
$data sera inséré à la place du premier espace réservé, $data à la place du second, etc. Mais attention : si vos index sont foirés, cela ne fonctionnera pas.

Espaces réservés nommés

# le premier argument est le nom de l'espace réservé # il commence généralement par deux points # bien que cela fonctionne sans eux $STH->bindParam(":name", $name);
Ici, vous pouvez également transmettre un tableau, mais il doit être associatif. Les clés doivent être, comme vous pouvez le deviner, les noms des espaces réservés.
# les données que nous insérons $data = array("name" => "Cathy", "addr" => "9 Dark and Twisty", "city" => "Cardiff"); $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) valeurs ​​(:name, :addr, :city)"); $STH->exécuter($data);
L'un des avantages de l'utilisation d'espaces réservés nommés est la possibilité d'insérer des objets directement dans la base de données si les noms de propriété correspondent aux noms de paramètres. Par exemple, vous pouvez insérer des données comme celles-ci :
# classe pour une personne de classe d'objet simple ( public $name; public $addr; public $city; function __construct($n,$a,$c) ( $this->name = $n; $this->addr = $ a ; $this->city = $c; ) # ainsi de suite... ) $cathy = nouvelle personne("Cathy","9 Dark and Twisty","Cardiff"); # et voici la partie intéressante $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values ​​​​(:name, :addr, :city)"); $STH->exécuter((array)$cathy);
La conversion d'un objet en tableau pendant execute() entraîne le traitement des propriétés comme des clés de tableau.

Échantillonnage de données



Les données peuvent être récupérées à l'aide de la méthode ->fetch(). Avant de l'appeler, il convient d'indiquer explicitement sous quelle forme vous en avez besoin. Il existe plusieurs options :
  • PDO::FETCH_ASSOC : renvoie un tableau avec les noms de colonnes comme clés
  • PDO::FETCH_BOTH (par défaut) : renvoie un tableau avec des index à la fois sous forme de noms de colonnes et de leurs numéros de série
  • PDO::FETCH_BOUND : attribue des valeurs de colonne aux variables correspondantes spécifiées à l'aide de la méthode ->bindColumn()
  • PDO::FETCH_CLASS : attribue des valeurs de colonne aux propriétés correspondantes de la classe spécifiée. S'il n'y a pas de propriété pour une colonne, elle sera créée
  • PDO::FETCH_INTO : met à jour une instance existante de la classe spécifiée
  • PDO::FETCH_LAZY : combine PDO::FETCH_BOTH et PDO::FETCH_OBJ
  • PDO::FETCH_NUM : renvoie un tableau avec des clés comme numéros de colonne
  • PDO::FETCH_OBJ : renvoie un objet anonyme avec des propriétés correspondant aux noms de colonnes
En pratique, vous en aurez généralement besoin de trois : FETCH_ASSOC, FETCH_CLASS et FETCH_OBJ. Pour spécifier le format des données, utilisez la syntaxe suivante :
$STH->setFetchMode(PDO::FETCH_ASSOC);
Vous pouvez également le définir directement lors de l’appel de la méthode ->fetch().

FETCH_ASSOC

Ce format crée un tableau associatif avec des noms de colonnes comme indices. Il devrait être familier à ceux qui utilisent les extensions mysql/mysqli.
# puisqu'il s'agit d'une requête normale sans espaces réservés, # vous pouvez immédiatement utiliser la méthode query() $STH = $DBH->query("SELECT name, addr, city from folks"); # définit le mode de récupération $STH->setFetchMode(PDO::FETCH_ASSOC); while($row = $STH->fetch()) ( echo $row["name"] . "\n"; echo $row["addr"] . "\n"; echo $row["city"] . "\n" ;
La boucle while() parcourra l'intégralité du résultat de la requête.

FETCH_OBJ

Ce type d'acquisition de données crée une instance de la classe std pour chaque ligne.
# créer une requête $STH = $DBH->query("SELECT nom, adresse, ville parmi les gens"); # sélectionnez le mode de récupération $STH->setFetchMode(PDO::FETCH_OBJ); # affiche le résultat while($row = $STH->fetch()) ( echo $row->name . "\n"; echo $row->addr . "\n"; echo $row->city . " \n"; )

FETCH_CLASS

Lors de l'utilisation de fetch_class, les données sont écrites dans les instances de la classe spécifiée. Dans ce cas, des valeurs sont attribuées aux propriétés de l'objet AVANT d'appeler le constructeur. Si les propriétés dont les noms correspondent aux noms de colonnes n'existent pas, elles seront créées automatiquement (avec la portée publique).

Si vos données nécessitent un traitement obligatoire immédiatement après leur réception de la base de données, elles peuvent être implémentées dans le constructeur de classe.

Par exemple, prenons une situation dans laquelle vous devez masquer une partie de l'adresse résidentielle d'une personne.
class secret_person ( public $name; public $addr; public $city; public $other_data; function __construct($other = "") ( $this->addr = preg_replace("//", "x", $this-> adresse); $this->other_data = $other;
Lors de la création d'un objet, toutes les lettres latines minuscules doivent être remplacées par x. Allons vérifier:
$STH = $DBH->query("SELECT nom, adresse, ville parmi les gens"); $STH->setFetchMode(PDO::FETCH_CLASS, "secret_person"); while($obj = $STH->fetch()) ( echo $obj->addr; )
Si l'adresse dans la base de données ressemble à « 5 Rosebud », alors le résultat sera « 5 Rxxxxxx ».

Bien sûr, vous souhaiterez parfois que le constructeur soit appelé AVANT d'attribuer des valeurs. PDO le permet également.
$STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "secret_person");
Maintenant que vous avez complété l'exemple précédent avec une option supplémentaire (PDO::FETCH_PROPS_LATE), l'adresse ne sera pas modifiée, puisque rien ne se passe après l'écriture des valeurs.

Enfin, si nécessaire, vous pouvez passer des arguments au constructeur directement lors de la création de l'objet :
$STH->setFetchMode(PDO::FETCH_CLASS, "secret_person", array("stuff"));
Vous pouvez même passer différents arguments à chaque objet :
$je = 0 ; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) ( // faire quelque chose $i++; )

Autres méthodes utiles

Bien que cet article ne puisse pas (et ne tente pas de) couvrir tous les aspects du travail avec PDO (c'est un module énorme !), les quelques fonctionnalités suivantes ne peuvent être laissées de côté sans être mentionnées.
$DBH->lastInsertId();
La méthode ->lastInsertId() renvoie l'identifiant du dernier enregistrement inséré. Il est à noter qu'il est toujours appelé sur un objet de base de données (appelé $DBH dans cet article), et non sur un objet avec une expression ($STH).
$DBH->exec("DELETE FROM les gens WHERE 1"); $DBH->exec("SET time_zone = "-8:00"");
La méthode ->exec() est utilisée pour les opérations qui ne renvoient aucune donnée autre que le nombre d'enregistrements concernés.
$safe = $DBH->quote($unsafe);
La méthode ->quote() place des guillemets dans les données de chaîne afin de pouvoir les utiliser en toute sécurité dans les requêtes. Utile si vous n'utilisez pas d'instructions préparées.
$rows_affected = $STH->rowCount();
La méthode ->rowCount() renvoie le nombre d'enregistrements ayant participé à l'opération. Malheureusement, cette fonction ne fonctionnait pas avec les requêtes SELECT jusqu'à PHP 5.1.6. S'il n'est pas possible de mettre à jour la version PHP, le nombre d'enregistrements peut être obtenu comme ceci :
$sql = "SELECT COUNT(*) FROM people"; if ($STH = $DBH->query($sql)) ( # vérifier le nombre d'enregistrements if ($STH->fetchColumn() > 0) ( # faire une sélection complète ici car les données ont été trouvées ! ) else ( # imprimer un message indiquant qu'aucune donnée satisfaisant la demande n'a été trouvée) )

Conclusion

J'espère que ce matériel aidera certains d'entre vous à migrer depuis les extensions mysql et mysqli.


3 juin 2018 Andreï Tchernychov Tutoriel de traduction 1737 0

PDO est l'acronyme de PHP Data Objects : c'est une extension PHP permettant de travailler avec des bases de données utilisant des objets. L'un de ses avantages réside dans le fait qu'il n'est pas directement lié à une base de données spécifique : son interface permet d'accéder à plusieurs environnements différents, parmi lesquels : MySQL, SQLite, PostgreSQL, Microsoft SQL Server.

Ce guide vise à fournir un aperçu complet de PDO et à guider le lecteur étape par étape depuis la création et la connexion à une base de données, jusqu'au choix des méthodes de récupération les plus appropriées, en montrant comment créer des requêtes préparées et en décrivant les modes d'erreur possibles.

Création d'une base de données et d'une table de test

Tout d'abord, nous allons créer une base de données :

CRÉER UNE BASE DE DONNÉES solar_system ; ACCORDEZ TOUS LES PRIVILÈGES SUR solar_system.* À "testuser"@"localhost" IDENTIFIÉ PAR "testpassword" ;

Nous avons accordé à l'utilisateur testuser tous les privilèges dans la base de données solar_system en utilisant testpassword comme mot de passe. Créons maintenant un tableau et remplissons-le avec quelques informations :

UTILISER le système_solaire ; CREATE TABLE planètes (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), nom VARCHAR(10) NOT NULL, couleur VARCHAR(10) NOT NULL) ; INSERT INTO planètes(nom, couleur) VALUES("terre", "bleu"), ("mars", "rouge"), ("Jupiter", "étrange");

Description de la connexion DSN (Data Source Name)

Maintenant que nous avons une base de données, nous devons définir le DSN. DSN signifie Data Source Name et est un ensemble d'informations nécessaires pour se connecter à une base de données, DSN se présente sous la forme d'une chaîne. La syntaxe diffère selon la base de données à laquelle vous devez vous connecter, mais comme nous utilisons MySQL/MariaDB, nous devons définir les éléments suivants :

  • Type de pilote utilisé pour la connexion ;
  • Le nom de l'ordinateur hôte sur lequel la base de données est exécutée ;
  • Port de connexion (en option) ;
  • Nom de la base de données;
  • Encodage (facultatif).

Le format de chaîne dans notre cas sera comme ceci (nous le stockerons dans la variable $dsn) :

$dsn = "mysql:host=localhost;port=3306;dbname=solar_system;charset=utf8";

Tout d'abord, nous définissons le préfixe de la base de données ou le préfixe de la base de données. Dans ce cas, puisque nous nous connectons à une base de données de type MySQL/MariaDB, nous utilisons mysql. Nous avons ensuite séparé le préfixe du reste de la ligne par un deux-points, et chaque section suivante a été séparée du reste par un point-virgule.

Dans les deux sections suivantes, nous avons spécifié le nom d'hôte sur lequel la base de données s'exécute et le port utilisé pour la connexion. Si aucun port n'est spécifié, le port par défaut sera utilisé, dans ce cas 3306. Immédiatement après le nom de la base de données est charset .

Création d'un objet PDO

Maintenant que notre DSN est prêt, nous allons commencer à créer l'objet PDO. Le constructeur PDO utilise la chaîne DSN comme premier paramètre, le nom d'utilisateur de la base de données comme deuxième paramètre, le mot de passe comme troisième et un tableau de paramètres facultatif comme quatrième.

$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = nouveau PDO($dsn, "testuser", "testpassword", $options);

Les paramètres peuvent également être définis après la création de l'objet, à l'aide de la méthode SetAttribute() :

$pdo->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Configuration de PDO pour afficher les erreurs

Jetons un coup d'œil à certaines des options disponibles pour PDO::ATTR_ERRMODE. Ces options sont extrêmement importantes car elles déterminent le comportement de PDO lorsque des erreurs se produisent. Options possibles :

PDO::ERRMODE_SILENT

Option par défaut. PDO lancera simplement un code d'erreur et un message d'erreur. Ils peuvent être obtenus à l’aide des méthodes errorCode() et errorInfo().

PDO::ERRMODE_EXCEPTION

Cette option est, à mon avis, recommandée. Avec son aide, en plus d'émettre un code d'erreur et des informations, PDO lancera une PDOException, qui interrompra l'exécution du script, et elle est également utile pour les transactions PDO (nous les examinerons un peu plus tard).

PDO : ERRMODE_WARNING

Avec cette option, PDO affichera un code d'erreur et un message tout comme PDO::ERRMODE_SILENT , mais affichera également un avertissement AVERTISSEMENT qui n'interrompra pas le script.

Définition de la méthode d'échantillonnage par défaut

Un autre paramètre important est régulé à l'aide de la constante PDO::DEFAULT_FETCH_MODE. Il permet de configurer le fonctionnement par défaut de la méthode fetch(), qui sera utilisée pour obtenir les résultats de la requête. Voici les options les plus couramment utilisées :

PDO::FETCH_BOTH

Lors de son utilisation, les résultats obtenus seront indexés à la fois par nombres entiers et par noms de colonnes. L’utiliser dans une méthode pour obtenir une ligne d’un tableau de planètes nous donnera les résultats suivants :

$stmt = $pdo->query("SELECT * FROM planètes"); $results = $stmt->fetch(PDO::FETCH_BOTH); Tableau ( => 1 => 1 => terre => terre => bleu => bleu)

PDO::FETCH_ASSOC

Avec cette constante, les résultats seront écrits dans un tableau associatif dans lequel chaque clé sera un nom de colonne, et chaque valeur représentera une valeur spécifique dans la ligne :

$stmt = $pdo->query("SELECT * FROM planètes"); $results = $stmt->fetch(PDO::FETCH_ASSOC); Tableau ( => 1 => terre => bleu)

PDO : FETCH_NUM

En utilisant la constante PDO::FETCH_NUM, nous obtenons un tableau indexé 0 :

Tableau ( => 1 => terre => bleu)

PDO::FETCH_COLUMN

Cette constante est utile pour obtenir uniquement les valeurs d'une colonne, et la méthode renverra tous les résultats dans un simple tableau unidimensionnel. Par exemple, voici une demande :

$stmt = $pdo->query("SELECT nom FROM planètes");

Par conséquent:

Tableau ( => terre => mars => jupiter)

PDO :: FETCH_KEY_PAIR

Cette constante est utile lorsque vous devez obtenir des valeurs de deux colonnes. La méthode fetchAll() renverra les résultats sous forme de tableau associatif. Dans ce tableau, les données de la première colonne seront spécifiées sous forme de clés, et de la seconde - sous forme de valeurs :

$stmt = $pdo->query("SELECT nom, couleur FROM planètes"); $result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

Par conséquent:

Tableau ( => bleu => rouge => étrange)

PDO :: FETCH_OBJECT

Lors de l'utilisation de la constante PDO::FETCH_OBJECT, un objet anonyme sera créé pour chaque ligne récupérée. Ses propriétés (publiques) porteront le même nom que les colonnes et les résultats de la requête seront utilisés comme valeurs. L'utilisation de cette méthode pour la même requête que ci-dessus produira le résultat suivant :

$results = $stmt->fetch(PDO::FETCH_OBJ); Objet stdClass ( => terre => bleu)

PDO::FETCH_CLASS

Comme la constante précédente, cela attribuera les valeurs des colonnes aux propriétés de l'objet, mais dans ce cas il faut configurer une classe existante qui sera utilisée pour créer l'objet. Pour démonstration, nous allons d’abord créer une classe :

Classe Planète ( private $name; private $color; public function setName($planet_name) ( $this->name = $planet_name; ) public function setColor($planet_color) ( $this->color = $planet_color; ) public function getName () ( return $this->name; ) fonction publique getColor() ( return $this->color; ) )

Ne faites pas attention à la simplicité du code, regardons mieux la classe Planet que nous avons créée : elle a private dans ses propriétés et la classe n'a pas de constructeur. Essayons maintenant d'obtenir des résultats.

Lorsque vous utilisez fetch() avec PDO::FETCH_CLASS, vous devez utiliser la méthode setFetchMode() sur l'objet avant de tenter de récupérer les données, par exemple :

$stmt = $pdo->query("SELECT nom, couleur FROM planètes"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planète");

Nous spécifions la constante PDO::FETCH_CLASS comme premier argument de la méthode setFetchMode() et le nom de la classe utilisée pour créer l'objet (dans notre cas « Planète ») comme deuxième argument. Exécutons maintenant le code :

$planète = $stmt->fetch();

Cela devrait donner un objet Planet :

Var_dump($planète); Objet planète ( => terre => bleu)

Remarquez comment les valeurs renvoyées par la requête ont été attribuées aux caractéristiques correspondantes de l'objet, même si elles sont privées.

Affectation de caractéristiques après la création d'un objet

La classe « Planète » n'avait pas de constructeur spécifique, il n'y avait donc aucun problème d'attribution de caractéristiques ; mais que se passe-t-il si la classe a un constructeur dans lequel les caractéristiques sont définies et modifiées ? Étant donné que les valeurs sont attribuées avant l'exécution du constructeur, elles seront écrasées.

PDO permet de fournir la constante FETCH_PROPS_LATE : lorsqu'elle est utilisée, les valeurs seront attribuées après la création de l'objet. Exemple:

Classe Planète ( private $name; private $color; public function __construct($name = lune, $color = gray) ( $this->name = $name; $this->color = $color; ) public function setName($ nom_planète) ( $this->name = $planet_name; ) fonction publique setColor($planet_color) ( $this->color = $planet_color; ) fonction publique getName() ( return $this->name; ) fonction publique getColor() (retour $this->color; ) )

Nous avons modifié notre classe Planet pour créer un constructeur qui prendra deux arguments : name name et color . Ces arguments ont les valeurs de base lune et gris, ce qui signifie que si aucune autre valeur n'est donnée, celles-ci seront définies.

Dans ce cas, si nous n'utilisons pas FETCH_PROPS_LATE, quelles que soient les valeurs obtenues à partir de la base de données, toutes les caractéristiques resteront basiques, car lors du processus de création de l'objet, elles seront écrasées. Pour vérifier cela, exécutons la requête suivante :

$stmt = $pdo->query("SELECT nom, couleur FROM solar_system WHERE nom = "terre""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planète"); $planète = $stmt->fetch();

Jetons maintenant un œil à l'objet Planet et vérifions quelles valeurs correspondent à ses caractéristiques :

Var_dump($planète); object(Planète)#2 (2) ( ["name":"Planète":private]=> string(4) "moon" ["color":"Planète":private]=> string(4) "gris" )

Comme prévu, les valeurs extraites de la base de données ont été écrasées par les valeurs par défaut. Nous allons maintenant démontrer la solution aux problèmes en utilisant la constante FETCH_PROPS_LATE (et la même requête que la précédente) :

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planète"); $planète = $stmt->fetch(); var_dump($planète); object(Planète)#4 (2) ( ["name":"Planète":private]=> string(5) "terre" ["color":"Planète":private]=> string(4) "bleu" )

Finalement, le résultat souhaité a été obtenu. Mais que se passe-t-il si le constructeur de classe n'a pas de valeurs de base et qu'elles doivent être spécifiées ? C'est déjà plus simple : nous pouvons définir les paramètres du constructeur sous la forme d'un tableau, comme troisième argument après le nom de la classe, en utilisant la méthode setFetchMode(). Par exemple, changeons le constructeur :

Classe Planète ( private $name; private $color; public function __construct($name, $color) ( $this->name = $name; $this->color = $color; ) [...] )

Les arguments du constructeur sont maintenant obligatoires, nous exécutons donc :

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planète", ["lune", "gris"]);

Dans ce cas, les paramètres que nous précisons servent uniquement de valeurs de base nécessaires au fonctionnement de l'objet sans erreur : ils seront écrasés par les valeurs de la base de données.

Récupération de plusieurs objets

Il est bien entendu possible d'obtenir plusieurs résultats à la fois sous forme d'objets, soit en utilisant la méthode fetch(), soit via une boucle :

While ($planet = $stmt->fetch()) ( // Quelque chose à voir avec les résultats )

Ou obtenir tous les résultats en même temps. Dans ce cas, comme mentionné précédemment, lors de l'utilisation de la méthode fetchAll(), vous devrez spécifier le mode de récupération non pas avant d'exécuter la méthode, mais au moment de son exécution :

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, "Planète", ["lune", "gris"]);

PDO::FETCH_INTO

Lors de l'utilisation de cette constante, PDO ne crée pas de nouvel objet, mais met à jour les caractéristiques d'un objet existant, mais uniquement s'il est public ou si la méthode __set() est utilisée à l'intérieur de l'objet.

Préparé contre des demandes directes

PDO a deux manières de travailler avec les requêtes : en utilisant les requêtes directes et la plus fiable - les requêtes préparées.

Demandes directes

Il existe deux méthodes principales pour utiliser des requêtes directes : query() et exec() . Le premier crée un objet PDOStatemnt, accessible via les méthodes fetch() ou fetchAll() : si vous les utilisez dans les cas où la table ne change pas, comme SELECT .

La deuxième méthode, à la place, renvoie le numéro de la ligne qui a été modifiée par la requête : nous l'utilisons dans les cas de remplacement de lignes, comme INSERT, DELETE ou UPDATE. Les requêtes directes ne doivent être utilisées que dans les cas où il n'y a aucune variable dans les requêtes et où il n'y a aucun doute sur la sécurité de la méthode.

Requêtes préparées

PDO prend également en charge les requêtes préparées en deux étapes : elles sont utiles lorsque les requêtes ont des variables, et sont plus sûres en général puisque la méthode prepare() fera tout le travail nécessaire à notre place. Voyons comment les variables sont utilisées. Imaginons que nous souhaitions insérer les caractéristiques d'une planète dans le tableau Planètes. Tout d’abord, préparons une demande :

$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(?, ?)");

Comme indiqué précédemment, nous utilisons la méthode prepare() qui prend la requête SQL comme argument, en utilisant des valeurs temporaires pour les variables. Les valeurs temporaires peuvent être de deux types : positionnelles et nominales.

Positionnel

En utilisant? valeurs temporaires positionnelles, le code est plus concis, mais il faut spécifier les données à insérer dans le même ordre que les noms de colonnes dans le tableau fourni en argument de la méthodeexecute() :

$stmt->execute([$planète->nom, $planète->couleur]);

Personnalisé

En utilisant des espaces réservés nommés, nous n’avons pas besoin d’un ordre spécifique, mais nous obtenons ainsi plus de code. Lors de l'exécution de la méthodeexecute(), nous devons fournir les données sous la forme d'un tableau associatif, où chaque clé est le nom de la valeur temporaire utilisée et la valeur associée est ce qui est transporté dans la requête. Par exemple, la requête précédente deviendrait :

$stmt = $pdo->prepare("INSERT INTO Planets(name, color) VALUES(:name, :color)"); $stmt->execute(["name" => $planet->name, "color" => $planet->color]);

Les méthodes préparer() et exécuter() peuvent toutes deux être utilisées pour des requêtes qui modifient ou récupèrent simplement des informations de la base de données. Dans le premier cas, nous utilisons les méthodes fetch listées ci-dessus pour obtenir des informations, et dans le second, nous utilisons la méthode rowCount().

Méthodes bindValue() et bindParam()

Les méthodes bindValue() et bindParam() peuvent également être utilisées pour fournir les valeurs qui seront insérées dans la requête. Le premier lie la valeur d'une variable donnée à une valeur temporaire positionnelle ou nommée utilisée lors de la préparation de la requête. En prenant le cas précédent comme exemple, nous ferons :

$stmt->bindValue("nom", $planète->nom, PDO::PARAM_STR);

Nous lions la valeur de $planet->name à une valeur temporaire:name . Notez qu'en utilisant à la fois les méthodes bindValue() et bindParam(), nous pouvons également spécifier le type de la variable comme troisième argument en utilisant une constante PDO appropriée, dans ce cas PDO::PARAM_STR .

En utilisant bindParam() à la place, nous pouvons lier la variable à une valeur temporaire appropriée utilisée dans la préparation de la requête. Notez que dans ce cas, la variable est liée à une référence et sa valeur ne sera modifiée en temporaire que lors de l'exécution de la méthodeexecute(). La syntaxe est la même que la dernière fois :

$stmt->bindParam("nom", $planète->nom, PDO::PARAM_STR)

Nous avons lié la variable, pas sa valeur, $planet->name à:name ! Comme indiqué ci-dessus, le remplacement n'aura lieu que lorsque la méthodeexecute() sera exécutée, donc la valeur temporaire sera remplacée par la valeur de la variable à ce moment-là.

Transactions AOP

Les transactions vous permettent de maintenir la cohérence lors de l'exécution de plusieurs requêtes. Toutes les requêtes sont exécutées par lots et ne sont appliquées à la base de données que si elles réussissent toutes. Les transactions ne fonctionneront pas avec toutes les bases de données, ni avec toutes les constructions SQL, car certaines d'entre elles posent problème.

À titre d'exemple extrême et étrange, imaginez que l'utilisateur doive sélectionner une liste de planètes et qu'à chaque fois qu'il effectue une nouvelle sélection, il doive supprimer la précédente de la base de données avant d'en insérer une nouvelle. Que se passe-t-il si la suppression a lieu mais pas l'insertion ? Nous aurons un utilisateur sans planètes ! Fondamentalement, les transactions sont appliquées comme ceci :

$pdo->beginTransaction(); essayez ( $stmt1 = $pdo->exec("DELETE FROM Planets"); $stmt2 = $pdo->prepare("INSERT INTO Planets(name, color) VALUES (?, ?)"); foreach ($planètes comme $planet) ( $stmt2->execute([$planet->getName(), $planet->getColor()]); ) $pdo->commit() ) catch (PDOException $e) ( $pdo-> rollBack ();

Tout d'abord, la méthode beginTransaction() sur l'objet PDO désactive la validation automatique de la requête, puis les requêtes sont démarrées dans l'ordre requis. À ce stade, à moins qu'une exception PDOException ne se produise, les requêtes sont automatiquement transmises via la méthode commit() ; sinon, les transactions sont annulées via la méthode rollBack() et la validation automatique est restaurée.

De cette façon, avec plusieurs demandes, il y aura toujours une cohérence. C'est assez évident, mais les transactions PDO ne peuvent être utilisées que par PDO::ATTR_ERRMODE défini sur PDO::ERRMODE_EXCEPTION .

Framework Bootstrap : mise en page adaptative rapide

Cours vidéo étape par étape sur les bases de la mise en page adaptative dans le framework Bootstrap.

Apprenez à rédiger simplement, rapidement et efficacement grâce à un outil puissant et pratique.

Mise en page sur commande et payé.

Cours gratuit "Site sur WordPress"

Vous souhaitez maîtriser le CMS WordPress ?

Obtenez des cours sur la conception et la mise en page de sites Web sur WordPress.

Apprenez à travailler avec des thèmes et des mises en page coupées.

Cours vidéo gratuit sur la conception, la mise en page et l'installation d'un site Web sur le CMS WordPress !

* Passez la souris pour suspendre le défilement.

Retour avant

Bases du travail avec l'extension PDO

Aujourd'hui, nous allons discuter d'un sujet très intéressant : les bases du travail avec l'extension. AOP pour PHP.

PDO (objets de données PHP)- il s'agit simplement d'une interface qui permet de travailler avec différentes bases de données sans tenir compte de leurs spécificités. Avec PDO, nous pouvons facilement basculer et gérer différentes bases de données. Pour que ce soit plus clair, regardons un exemple.

Comment nous aurions dû nous connecter à la base de données avant MySQL?

Mysql_connect ($ hôte, $ utilisateur, $ mot de passe); mysql_select_db($db);

Pour se connecter à SQLite nous aurions dû écrire ainsi :

SQLite_open($db);

Si nous avons besoin d'une base de données PostgreSQL, alors vous devez l'écrire comme ceci :

Pg_connect("host=$host, dbname=$db, user=$user, password=$password");

Pas très pratique, non ? Il s'avère que si nous voulons changer la base de données, nous devrons refaire beaucoup de code. Et donc, pour résoudre ce problème, une extension PHP spéciale est apparue - AOP.

Voyons comment nous pouvons maintenant nous connecter à la base de données :

$db = new PDO("mysql:host=$host;dbname=$db", $user, $password);

$db = nouveau PDO("sqlite:$db);

PostgreSQL :

$db = new PDO("pgsql:host=$host;dbname=$db", $user, $password);

Comme vous pouvez le constater, tout est pareil, à l'exception de la ligne de connexion. C'est la seule différence.


Voyons maintenant comment nous devions exécuter les requêtes :

$sql = "INSERT INTO(nom, email) VALUES($nom, $email)"; // MySQL mysql_query($sql); // SQLite sqlite_query($sql); // PostgreSQL pg_query($sql);

Nous pouvons maintenant faire abstraction de ceci :

// PDO $result = $db->exec($sql);

Tous! Notre la requête sera exécutée quelle que soit la base de données que nous utilisons, et dans la variable résultat affichera le nombre de lignes affectées.

Cependant, nous ne pourrons pas sélectionner quelque chose dans la base de données de cette manière. Pour l'échantillonnage, nous devons utiliser non exécutif, UN requête.

$sql = "SÉLECTIONNER le nom des utilisateurs" ; $result = $db->query($sql);

Maintenant, allons N'oublions pas la sécurité, car toutes les données doivent être vérifiées. Comment faisions-nous avant ?

$sql = "SELECT * FROM utilisateurs WHERE nom = $nom"; $nom = $_POST["nom"]; // MySQL $nom = mysql_real_escape_string($nom); // SQLite $nom = sqlite_escape_string($nom); // PostgreSQL $nom = pg_escape_string($nom);

Maintenant, nous n'avons plus besoin de faire ça. AOP fera tout pour nous.

$nom = $db->quote($nom); $result = $db->query($sql);

PDO lui-même vérifiera tout et traitera les données transmises. Cool ? :) Encore plus cool à venir ! Nous allons continuer.

Comment avons-nous converti le résultat en tableau auparavant ? Regardons l'exemple d'une base de données MySQL.

$result = mysql_query($sql); // Donc $row = mysql_fetch_assoc($result); // Ou comme ça... $row = mysql_fetch_array($result, FETCH_ASSOC);

Tout comme le tableau associatif, nous pourrions également obtenir un tableau numéroté. Voyons maintenant comment cela se fait AOP:

$stmt = $db->query($sql); //Associatif $result = $stmt->FETCH(PDO::FETCH_ASSOC); // Numéroté $result = $stmt->FETCH(PDO::FETCH_NUM); // Les deux types de tableaux en même temps $result = $stmt->FETCH(PDO::FETCH_BOTH); // Objet $result = $stmt->FETCH(PDO::FETCH_OBJ);

Il est également très simple à utiliser :

// Echo associatif $result["name"]; // Echo numéroté $result; // Objet echo $result->name;

Pour les "paresseux", il y a ce truc :

$stmt = $db->query($sql); $result = $stmt->FETCH(PDO::FETCH_LAZY);

Il renvoie les 3 types à la fois. Ceux. Ce FETCH_BOTH Et FETCH_OBJ ensemble. Comme vous l'avez peut-être deviné, les données sont ensuite accessibles de trois manières :

Echo $result->nom ; echo $result["nom"]; echo $résultat ;

Cependant Aller chercher renvoie un seul enregistrement, donc si nous voulons obtenir tous les enregistrements, nous devons alors utiliser Récupérer tout.

$stmt = $db->query("SELECT * FROM utilisateurs"); $result = $stmt->FetchAll(PDO::FETCH_ASSOC); foreach($result as $user) ( echo $user["name"]."
"; }

Mais il y a une autre chose intéressante liée à Aller chercher. Avec son aide, nous pouvons remplir notre classe avec les données de la base de données automatiquement.

Utilisateur de classe ( public $login; public $id; public function showInfo() ( echo " ".$this->id.""." : ".$this->connexion."
"; ) ) $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $stmt = $db->query("SELECT * FROM `users`"); $ result = $stmt->fetchAll(PDO::FETCH_CLASS, "User"); foreach($result as $user) ( $user->showInfo(); )

Comme vous pouvez le constater, tout est très simple. Il suffit de spécifier une constante FETCH_CLASS et séparé par une virgule entre guillemets, le nom de la classe où les données seront insérées.

Ensuite, nous parcourons l’objet et affichons les informations dont nous avons besoin.
Attention! Les noms des propriétés de la classe doivent correspondre aux noms des champs de la base de données.

Entre autres choses, nous pouvons créer ce qu'on appelle requêtes préparées. Quels sont leurs avantages ?

1. Nous pouvons préparer une requête une fois, puis l'exécuter autant de fois que nécessaire. Et avec les mêmes paramètres et d’autres.

Lorsqu'une requête est préparée, le SGBD l'analyse, la compile et optimise son plan d'exécution. Dans le cas de requêtes complexes, le temps d'exécution sera perceptible si nous l'exécutons avec des paramètres différents. Dans le cas de requêtes préparées, cette opération est effectuée une seule fois et on perd donc moins de temps.

2. Les paramètres de requête préparés n'ont pas besoin d'être entourés de guillemets ; le pilote le fait automatiquement. Si l'application utilise uniquement des requêtes préparées, les injections SQL sont presque impossibles.

PDO peut émuler des requêtes préparées, s'ils ne sont pas pris en charge par le pilote. Voyons maintenant comment les utiliser ?

$stmt = $db->prepare("INSERT INTO utilisateurs (nom, login) VALUES (:name, :login)"); $stmt->bindParam(":name", $name); $stmt->bindParam(":login", $login); // Insère une ligne avec ces valeurs $name = "vasya"; $ connexion = "vasya123"; $stmt->exécuter(); // Maintenant une autre ligne avec des valeurs différentes $name = "petya"; $connexion = "petya123"; $stmt->exécuter();

Méthode bindParam nous permet de définir des paramètres. Je pense que tout est clair ici. Tout d'abord, à l'endroit où nous voulons que les données soient insérées, écrivez la ligne suivante " :Nom". Et puis on indique d'où ils proviendront. Dans ce cas, ils seront extraits des variables nom Et se connecter.

Nous pouvons maintenant utiliser cette requête avec différents paramètres autant de fois que nous le souhaitons, et pour l'exécuter, nous devons appeler la méthode exécuter. C'étaient nommé choix. Il y a aussi pas nommé.

$stmt = $db->prepare("INSERT INTO users (name, login) VALUES (?, ?)"); // Les données de la variable name seront insérées à la place du premier point d'interrogation $stmt->bindParam(1, $name); // Les données de la variable de connexion seront insérées à la place du deuxième point d'interrogation $stmt->bindParam(2, $login); // Insère une ligne avec ces valeurs $name = "vasya"; $ connexion = "vasya123"; $stmt->exécuter(); // Maintenant une autre ligne avec des valeurs différentes $name = "petya"; $ connexion = "petya123"; $stmt->exécuter();

Point suivant - Comment détecter les erreurs ?

Il y a une classe pour ça PDOException. Je recommande d'écrire toutes vos demandes dans un bloc essayer-attraper.

Essayez ( $db = new PDO("myql:host=localhost;dbname=test", "root", ""); $stmt = $db->query("SELECT * FROM users"); $result = $stmt ->fetch(PDO::FETCH_ASSOC); echo $result["login"]; catch(PDOException $e) ( echo "Erreur : ".$e->getMessage()."
"; echo "Sur la ligne : ".$e->getLine(); )

Ici, nous avons fait une erreur et écrit myql au lieu de mysql. Et la classe PDOException nous écrira à ce sujet.

Il existe plusieurs méthodes, mais les plus couramment utilisées sont obtenirMessage() qui nous renvoie le texte d'erreur et getLine(), qui renvoie le numéro de ligne où l'erreur a été commise.

Et enfin, parlons de transactions. Je vais d'abord donner le code.

Essayez ( $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $db->beginTransaction(); $stmt = $db->exec("INSERT INTO `users `(`login`) VALUES("login1")"); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES("login2")"); $stmt = $db- >exec("INSERT INTO `users`(`login`) VALUES("login3")"); $db->commit( ); catch(PDOException $e) ( $db->rollBack(); )

Ici, nous commençons la transaction en utilisant la méthode commencerTransaction(). Vient ensuite un code de requête. Ensuite, nous appelons la méthode commettre() pour confirmer nos modifications. Si quelque chose ne va pas, alors dans le bloc attraper nous appelons la méthode retour en arriere(), ce qui ramènera toutes nos données à l'état précédent.

« Pourquoi ces transactions sont-elles réellement nécessaires ? - tu demandes. Pour répondre à cette question, considérons l’exemple que j’ai donné ci-dessus. Là, vous insérez la valeur dans le champ "login" connexion1, connexion2, connexion3.

Imaginons qu'après avoir inséré connexion1 Et connexion2, une erreur s'est produite. Il s'avère que ces données sont insérées, et connexion3- Non. Dans de nombreux cas, cela est inacceptable et entraînera le blocage de l'application à l'avenir.

C’est précisément pour éviter de telles situations que des transactions sont nécessaires. Si notre script échoue, alors la méthode retour en arriere() remettra tout à sa forme originale. Ceux. connexion1 Et connexion2 ne sera pas non plus inséré. Imitons cette erreur.

Essayez ( $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $db->beginTransaction(); $stmt = $db->exec("INSERT INTO `users `(`login`) VALUES("login1")"); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES("login2")"); exit("erreur") ; $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES("login3")"); $db->commit(); ();

Après l'insertion connexion1 Et connexion2 on sort du script en utilisant la fonction sortie(). On lance une exception, on se retrouve dans un bloc attraper, puis nous remettons tout à sa forme originale. Maintenant, si nous regardons dans la base de données, nous n'y verrons pas connexion1 Et connexion2.

Nous terminerons à ce stade. Évidemment, nous n'avons pas couvert ici tout ce que PDO nous offre, mais nous avons appris les bases de son utilisation. Vous pouvez toujours trouver des informations plus détaillées sur cette extension sur le site officiel de PHP.

Le matériel a été préparé par Vladislav Andreev spécifiquement pour le site Web

P.S. Vous souhaitez aller plus loin dans la maîtrise de PHP et de la POO ? Faites attention aux leçons premium sur divers aspects de la création de sites Web, y compris la programmation en PHP, ainsi qu'à un cours gratuit sur la création de votre propre système CMS en PHP à partir de zéro en utilisant la POO :

Vous avez aimé le matériel et souhaitez me remercier ?
Partagez simplement avec vos amis et collègues !


mob_info