Maison > Article > développement back-end > En trois minutes, vous découvrirez le PDO d'initialisation et les opérations d'instruction SQL originales en PHP.
Cet article vous présentera les opérations d'initialisation du PDO et des instructions SQL originales en PHP. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.
PDO est devenu le standard de facto pour exploiter des bases de données en PHP. Y compris les frameworks actuels et diverses bibliothèques de classes, tous utilisent PDO comme méthode de connexion à la base de données. Fondamentalement, nous utilisons uniquement mysqli pour faire fonctionner la base de données lors de l'écriture de code de test simple ou de petites fonctions. Notez que l’extension mysql normale est obsolète !
Voyons d'abord comment une instance PDO est initialisée.
$dns = 'mysql:host=localhost;dbname=blog_test;port=3306;charset=utf8'; $pdo = new PDO($dns, 'root', '');
Dans des circonstances normales, nous pouvons obtenir un objet PDO en passant les paramètres de construction lors de son instanciation directement. De cette façon, nous avons établi une connexion avec la base de données. Si la connexion échoue, c'est-à-dire s'il y a un problème avec les paramètres écrits, une exception sera signalée directement lors de l'instanciation.
Les paramètres de l'objet PDO incluent les informations DNS, le nom d'utilisateur, le mot de passe et un autre paramètre qui peut définir certaines propriétés de la connexion PDO. Nous verrons son utilisation plus tard.
Le premier paramètre du paramètre de construction PDO est une chaîne DNS. Utilisez des points-virgules dans cette chaîne pour séparer les différents contenus de paramètres. Le contenu qui peut y être défini comprend :
Le préfixe DSN, qui est le type de base de données auquel nous voulons nous connecter. Les bases de données MySQL sont généralement définies directement à l'aide de mysql : comme ceci.
host, l'adresse de connexion, ici nous nous connectons à la base de données locale localhost
port, le numéro de port, MySQL par défaut est 3306, vous pouvez Ne pas écrire
dbname, le nom de la base de données à connecter est
unix_socket, vous pouvez spécifier le fichier MySQL Unix Socket
charset, le jeu de caractères connecté
Nous pouvons utiliser une fonction pour vérifier quelles extensions de base de données sont prises en charge dans l'environnement PHP actuel :
print_r(PDO::getAvailableDrivers());exit; // Array // ( // [0] => dblib // [1] => mysql // [2] => odbc // [3] => pgsql // [4] => sqlite // )
Le dernier paramètre du paramètre de construction PDO peut définir certains attributs de la connexion, tels que :
$pdo = new PDO($dns, 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); showPdoAttribute($pdo); // …… // PDO::ATTR_ERRMODE: 2 // ……
méthode showPdoAttribute() est notre propre encapsulation pour afficher toutes les fonctions d'attribut de connexion.
// 显示pdo连接属性 function showPdoAttribute($pdo){ $attributes = array( "DRIVER_NAME", "AUTOCOMMIT", "ERRMODE", "CASE", "CLIENT_VERSION", "CONNECTION_STATUS", "ORACLE_NULLS", "PERSISTENT", "SERVER_INFO", "SERVER_VERSION" ); foreach ($attributes as $val) { echo "PDO::ATTR_$val: "; echo $pdo->getAttribute(constant("PDO::ATTR_$val")) . "\n"; } }
Dans cette fonction, nous utilisons la méthode getAttribute() de l'instance PDO pour obtenir la valeur de l'attribut correspondante. Lorsque PDO::ATTR_ERRMODE n'est pas défini, sa valeur par défaut est 0, qui est la valeur correspondant à la constante PDO::ERRMODE_SILENT. Dans le code ci-dessus, nous le définissons sur PDO::ERRMODE_EXCEPTION, et le résultat de l'affichage de la sortie de l'attribut devient 2.
En plus de définir les attributs dans les paramètres du constructeur, nous pouvons également utiliser la méthode setAttribute() de l'instance PDO pour définir la valeur de l'attribut PDO.
pdo2 = new PDO($dns, 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); echo $pdo2->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE), PHP_EOL; // 4 // 设置属性 $pdo2->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); echo $pdo2->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE), PHP_EOL; // 2
Dans ce code, nous définissons PDO::ATTR_DEFAULT_FETCH_MODE sur PDO::FETCH_ASSOC . De cette façon, lors d'une requête utilisant cette connexion $pdo2, les résultats de sortie seront renvoyés sous la forme de paires clé-valeur de tableau. Nous entrerons immédiatement dans l'étude des fonctions liées aux requêtes.
Dans la plupart des cas, lors de l'utilisation de PDO, nous utiliserons ses capacités de prétraitement pour écrire des instructions SQL. Premièrement, les performances sont meilleures, et deuxièmement, plus sécurisées. . Cependant, ne parlons pas des problèmes de prétraitement aujourd'hui. Apprenons quelques fonctions associées de la manière la plus primitive d'exploiter directement les instructions SQL.
// 普通查询 - 遍历1 $stmt = $pdo->query('select * from zyblog_test_user limit 5'); foreach ($stmt as $row) { var_dump($row); } // array(8) { // ["id"]=> // string(3) "204" // [0]=> // string(3) "204" // ["username"]=> // string(5) "three" // [1]=> // string(5) "three" // ["password"]=> // string(6) "123123" // [2]=> // string(6) "123123" // ["salt"]=> // string(3) "ccc" // [3]=> // string(3) "ccc" // } // …… // 普通查询 - 遍历2 $stmt = $pdo->query('select * from zyblog_test_user limit 5'); while ($row = $stmt->fetch()) { var_dump($row); } // array(8) { // ["id"]=> // string(3) "204" // [0]=> // string(3) "204" // ["username"]=> // string(5) "three" // [1]=> // string(5) "three" // ["password"]=> // string(6) "123123" // [2]=> // string(6) "123123" // ["salt"]=> // string(3) "ccc" // [3]=> // string(3) "ccc" // } // ……
La méthode query() d'une instance PDO exécute une instruction de requête et renvoie un objet PDOStatement. En parcourant cet objet, vous pouvez obtenir l'ensemble de résultats de données interrogées.
Dans le code, nous utilisons deux méthodes pour parcourir, mais en fait elles ont le même effet. Ici, nous voulons nous concentrer sur le format des données renvoyées. On peut voir que les données sont renvoyées sous forme de tableau et sous deux formes, l'une est le nom de clé défini par la base de données et l'autre est sous forme d'indice.
En fait, dans la plupart des cas, nous n'avons besoin que de données sous la forme de paires clé-valeur de noms de clés de base de données. Il existe deux façons de procéder. L'une consiste à utiliser directement la connexion $pdo2 avec l'attribut par défaut PDO::ATTR_DEFAULT_FETCH_MODE que nous avons défini ci-dessus, et l'autre consiste à spécifier les attributs de la méthode query() lors de l'interrogation.
$stmt = $pdo2->query('select * from zyblog_test_user limit 5'); foreach ($stmt as $row) { var_dump($row); } // array(4) { // ["id"]=> // string(1) "5" // ["username"]=> // string(3) "two" // ["password"]=> // string(6) "123123" // ["salt"]=> // string(3) "bbb" // } // …… $stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_ASSOC); foreach ($stmt as $row) { var_dump($row); } // array(4) { // ["id"]=> // string(1) "5" // ["username"]=> // string(3) "two" // ["password"]=> // string(6) "123123" // ["salt"]=> // string(3) "bbb" // } // ……
Bien sûr, nous pouvons également renvoyer directement les données au format objet. De même, nous pouvons également utiliser des constantes prédéfinies pour spécifier query() ou les attributs de la connexion à l'instance PDO.
$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_OBJ); foreach ($stmt as $row) { var_dump($row); } // object(stdClass)#4 (4) { // ["id"]=> // string(1) "5" // ["username"]=> // string(3) "two" // ["password"]=> // string(6) "123123" // ["salt"]=> // string(3) "bbb" // } // ……
Les objets de l'ensemble de résultats renvoyés sous la forme d'objets ci-dessus sont de type stdClass, qui est le type de classe par défaut de PHP. Pouvons-nous donc définir une classe nous-mêmes, puis générer directement son jeu de résultats une fois la requête terminée ? Tout comme un framework ORM, il complète le mappage des données aux objets. Maintenant que j'ai dit cela, bien sûr, c'est possible, il suffit de regarder le code.
class user { public $id; public $username; public $password; public $salt; public function __construct() { echo 'func_num_args: ' . func_num_args(), PHP_EOL; echo 'func_get_args: '; var_dump(func_get_args()); } } class user2 { } // 返回指定对象 $u = new user; $stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_INTO, $u); foreach ($stmt as $row) { var_dump($row); } // object(user)#3 (4) { // ["id"]=> // string(1) "5" // ["username"]=> // string(3) "two" // ["password"]=> // string(6) "123123" // ["salt"]=> // string(3) "bbb" // } // …… // 空类测试 $u = new user2; $stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_INTO, $u); foreach ($stmt as $row) { var_dump($row); } // object(user2)#2 (4) { // ["id"]=> // string(1) "5" // ["username"]=> // string(3) "two" // ["password"]=> // string(6) "123123" // ["salt"]=> // string(3) "bbb" // } // ……
在这段代码中,我们定义了两个类,user 类有完整的和数据库字段对应的属性,还定义了一个构造方法(后面会用到)。而 user2 类则是一个空的类。通过测试结果来看,类的属性对于 PDO 来说并不重要。它会默认创建数据库查询到的字段属性,并将它赋值给对象。那么假如我们定义了一个 const 常量属性并给予相同的字段名称呢?大家可以自己尝试一下。
对于 user 和 user2 来说,我们将它实例化了并传递给了 query() ,并且指定了结果集格式为 PDO::FETCH_INTO ,这样就实现了获取对象结果集的能力。但是 PDO 远比你想象的强大,我们还可以直接用类模板来获取查询结果集。
// 根据类返回指定对象 $stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_CLASS, 'user', ['x1', 'x2']); foreach ($stmt as $row) { var_dump($row); } // func_num_args: 2 // func_get_args: array(2) { // [0]=> // string(2) "x1" // [1]=> // string(2) "x2" // } // object(user)#4 (4) { // ["id"]=> // string(1) "5" // ["username"]=> // string(3) "two" // ["password"]=> // string(6) "123123" // ["salt"]=> // string(3) "bbb" // } // ……
query() 方法直接使用查询结果集模式为 PDO::FETCH_CLASS ,并传递一个类模板的名称,PDO 就会在当前代码中查找有没有对应的类模板,获得的每个结果都会实例化一次。在这里,我们又多了一个参数,最后一个参数是一个数组,并且给了两个元素。估计有不少小伙伴已经看出来了,这个参数是传递给类的构造方法的。记住,使用这个模式,每个元素都会实例化一次,结果集中的每个元素都是新创建的类(object(user2)#3,#号后面的数字是不同的对象句柄id),而 PDO::FETCH_INTO 则是以引用的形式为每个元素赋值(object(user2)#3,#号后面的数字是相同的对象句柄id)。也就是说,我们使用 PDO::FETCH_INTO 模式的时候,修改一个元素的值,其它的元素也会跟着改变,如果使用一个数组去记录遍历的元素值,最后数组的结果也会是相同的最后一个元素的内容。
$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_INTO, $u); $resArr = []; foreach ($stmt as $row) { var_dump($row); $resArr[] = $row; } $resArr[0]->id = 55555; print_r($resArr); // Array // ( // [0] => user2 Object // ( // [id] => 55555 // [username] => two // [password] => 123123 // [salt] => bbb // ) // [1] => user2 Object // ( // [id] => 55555 // [username] => two // [password] => 123123 // [salt] => bbb // ) // [2] => user2 Object // ( // [id] => 55555 // [username] => two // [password] => 123123 // [salt] => bbb // ) // [3] => user2 Object // ( // [id] => 55555 // [username] => two // [password] => 123123 // [salt] => bbb // ) // [4] => user2 Object // ( // [id] => 55555 // [username] => two // [password] => 123123 // [salt] => bbb // ) // )
如何解决这个问题呢?最简单的方式就是在数组赋值的时候加个 clone 关键字呗!
最后轻松一点,我们看下 query() 方法还可以指定查询的某一个字段。
// 只返回第几个字段 $stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_COLUMN, 2); foreach ($stmt as $row) { var_dump($row); } // string(32) "bbff8283d0f90625015256b742b0e694" // string(6) "123123" // string(6) "123123" // string(6) "123123" // string(6) "123123"
除了查询之外的操作,我们也可以使用 exec() 方法来执行其他一些相应的 SQL 语句。
$count = $pdo->exec("insert into zyblog_test_user(`username`, `password`, `salt`) value('akk', 'bkk', 'ckk')"); $id = $pdo->lastInsertId(); var_dump($count); // int(1) var_dump($id); // string(3) "205"
exec() 返回的是影响的行数,如果我们执行这一条 SQL ,返回的就是成功添加了一行数据。如果要获得新增加数据的 id ,就要使用 lastInserId() 方法来获取。
$count = $pdo->exec("insert into zyblog_test_user(`username`, `password`, `salt`) value('akk', 'bkk', 'ckk', 'dkk')"); // Fatal error: Uncaught PDOException: SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1
执行错误的 SQL 语句,就像根据 PDO::ATTR_ERRMODE 属性的设置来返回错误信息。我们在最上面的实例化 PDO 代码中指定了错误形式是异常处理模式,所以这里直接就会报 PDOException 异常。
// 正常更新 $count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='{$id}'"); var_dump($count); // int(1) // 数据不变更新 $count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='{$id}'"); var_dump($count); // int(0) // 条件错误更新 $count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='123123123123'"); var_dump($count); // int(0) echo '===============', PHP_EOL;
同样的,在执行更新操作的时候,exec() 返回的也是受影响的行数。很多小伙伴会以这个进行判断是否更新成功,但如果数据没有修改,那么它返回的将是 0 ,SQL 语句的执行是没有问题的,逻辑上其实也没有问题。比如我们在后台打开了某条数据查看,然后并不想更新任何内容就直接点了提交,这时候不应该出现更新失败的提示。也就是说,在前端判断更新操作的时候,需要判断字段是否都有改变,如果没有改变的话那么不应该提示更新失败。这一点是业务逻辑上的考虑问题,如果你认为这样也是更新失败的话,那么这么报错也没有问题,一切以业务形式为主。
$count = $pdo->exec("delete from zyblog_test_user where id = '{$id}'"); var_dump($count); // int(1) // 条件错误删除 $count = $pdo->exec("delete from zyblog_test_user where id = '5555555555'"); var_dump($count); // int(0)
删除操作需要注意的问题和更新操作是一样的,那就是同样的 exec() 只是返回影响行数的问题,不过相对于更新操作来说,没有受影响的行数那肯定是删除失败的,没有数据被删除。同样的,这个失败的提示也请根据业务情况来具体分析。
不学不知道,一学吓一跳吧,简简单的一个 PDO 的创建和语句执行竟然有这么多的内容。对于我们的日常开发来说,掌握这些原理能够避免很多莫名其妙的问题,比如上面 exec() 只是返回影响行数在业务开发中如何判断操作是否成功的问题就很典型。好了,这只是第一篇,后面的学习不要落下了哦!
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202008/source/PHP%E4%B8%AD%E7%9A%84PDO%E6%93%8D%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%88%E4%B8%80%EF%BC%89%E5%88%9D%E5%A7%8B%E5%8C%96PDO%E5%8F%8A%E5%8E%9F%E5%A7%8BSQL%E8%AF%AD%E5%8F%A5%E6%93%8D%E4%BD%9C.php
推荐学习:php视频教程
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!