PDO vs MySQLi : la bataille des API de base de données PHP

藏色散人
Libérer: 2023-04-05 17:24:01
original
3018 Les gens l'ont consulté

PDO vs MySQLi : la bataille des API de base de données PHP

Introduction

L'époque de l'utilisation de l'extension mysql_ est révolue, depuis PHP 5.5 Ses méthodes ont été obsolètes et supprimées à partir de PHP 7. Mais Internet regorge encore d’anciens tutoriels que les débutants peuvent simplement copier/coller et utiliser avec les anciennes versions de PHP sur les plateformes d’hébergement mutualisé.

Si vous utilisez MySQL ou MariaDB en PHP, vous avez désormais la possibilité de MySQLi ou PDO. La première n'est qu'une version améliorée, prend en charge la procédure et la POO et ajoute des instructions préparées, tandis que la seconde est une couche d'abstraction qui vous permet d'utiliser une API unifiée pour les 12 pilotes de base de données qu'elle prend en charge. Bien que MySQL soit la base de données la plus populaire dans le monde PHP.

En théorie, nous n'avons pas besoin d'avoir une API spécifique au fournisseur pour chaque type de base de données existant, car il est beaucoup plus simple d'en utiliser une seule. Bien qu'il y ait certainement beaucoup de vérité là-dedans, le problème est que PDO_MYSQL ne possède pas toutes les fonctionnalités les plus récentes et les plus performantes de MySQLi. Honnêtement, je ne comprends pas pourquoi c'est le cas, car cela éliminerait complètement toute raison d'utiliser une API spécifique au fournisseur. Pourtant, j’imagine que la plupart des gens n’ont pas besoin de ces fonctionnalités supplémentaires, mais certains en ont certainement besoin.

Avantages du PDO

1. Méthodes d'acquisition utiles

2. Permet de transmettre directement des variables et des valeurs à exécuter

3. Possibilité de détecter automatiquement les types de variables (ce qui se passe réellement, c'est que lorsqu'ils sont envoyés au serveur, tout est traité comme une chaîne, mais converti au type correct. Cela fonctionne à 100 % dans les instructions préparées, mais dans certaines n'a aucun effet dans les cas extrêmes, comme en mode simulation)

4. Fournit une option pour mettre automatiquement en mémoire tampon les résultats à l'aide d'instructions préparées

5. Paramètres nommés (bien que désactiver le mode simulation dans PDO soit inutile car vous ne peut utiliser le même nom qu'une seule fois)

Avantages MySQL

1 Requête asynchrone

2. informations, telles que la mise à jour des lignes avec la même valeur (peut être définie dans PDO en tant que constructeur et ne peut pas être modifiée ultérieurement)

3. Méthode d'arrêt de la base de données correcte

4. ok si le mode simulation est activé dans PDO)

5. Utilisez des connexions persistantes pour effacer automatiquement

Les différences de code

PDO et MySQLi sont très similaires, mais ont une syntaxe légèrement différente. MySQLi suit l'ancienne convention PHP Snake_case, tandis que PDO utilise CamelCase. De plus, les méthodes de MySQLi sont utilisées comme propriétés d'objet, tandis que PDO utilise la syntaxe traditionnelle pour les fonctions.

PDO et MySQLi compliquent les choses en vous obligeant à utiliser deux méthodes distinctes pour utiliser les instructions préparées. Cependant, PDO élimine le besoin d’utiliser des fonctions de liaison dédiées.

Par exemple, dans l'API PostgreSQL spécifique au fournisseur, vous pouvez le faire.

Pour référence, voici un exemple de comment effectuer une requête "non préparée" pour obtenir un tableau associatif contenant MySQLi et PDO.

$arr = $mysqli->query("SELECT * FROM myTable")->fetch_all(MYSQLI_ASSOC);
Copier après la connexion
$arr = $pdo->query("SELECT * FROM myTable")->fetchAll(PDO::FETCH_ASSOC);
Copier après la connexion

En fait, le meilleur moyen est d'utiliser un wrapper, un générateur de requêtes ou un ORM. Bien que PDO puisse lier des valeurs directement lors de l'exécution, ce n'est toujours pas idéal. Dans la classe que j'ai créée, vous pouvez enchaîner tous les appels tout en transmettant des valeurs en tant que liaisons de paramètres de paramètres.

$arr = $mysqli->query("SELECT * FROM myTable WHERE id > ?", [12])->fetchAll('assoc');
Copier après la connexion

L'intégralité du tableau associatif est désormais stocké dans une variable de manière plus concise.

Créer une nouvelle connexion à la base de données

PDO

$dsn = "mysql:host=localhost;dbname=myDatabase;charset=utf8mb4";$options = [
  PDO::ATTR_EMULATE_PREPARES   => false, // turn off emulation mode for "real" prepared statements
  PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, //turn on errors in the form of exceptions
  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, //make the default fetch be an associative array];try {
  $pdo = new PDO($dsn, "username", "password", $options);} catch (Exception $e) {
  error_log($e->getMessage());
  exit('Something weird happened'); //something a user can understand}
Copier après la connexion

MySQLi

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);try {
  $mysqli = new mysqli("localhost", "username", "password", "databaseName");
  $mysqli->set_charset("utf8mb4");} catch(Exception $e) {
  error_log($e->getMessage());
  exit('Error connecting to database'); //Should be a message a typical user could understand}
Copier après la connexion

Insérer, mettre à jour, delete

PDO

$stmt = $pdo->prepare("INSERT INTO myTable (name, age) VALUES (?, ?)");
$stmt->execute([$_POST['name'], 29]);
$stmt = null;
Copier après la connexion

MySQLi

$stmt = $mysqli->prepare("UPDATE myTable SET name = ? WHERE id = ?");
$stmt->bind_param("si", $_POST['name'], $_SESSION['id']);
$stmt->execute();
$stmt->close();
Copier après la connexion

Notez que préparer() et exécuter() peuvent être liés à l'aide de PDO.

Obtenir le nombre de lignes concernées

PDO

$stmt->rowCount();
Copier après la connexion

MySQLi

$stmt->affected_rows;
Copier après la connexion

Insérer la dernière Clé primaire

Notez que les deux méthodes utilisent la variable de connexion, pas $stmt.

PDO

$pdo->lastInsertId();
Copier après la connexion

MySQLi

$mysqli->insert_id;
Copier après la connexion

Obtenir les lignes correspondantes

PDO

dans In PDO, le seul moyen d'y parvenir est de le définir comme option de connexion, en modifiant le comportement de rowCount(). Cela signifie que rowCount() renverra les lignes correspondantes ou les lignes modifiées pour l'ensemble de la connexion à la base de données, mais pas les deux.

$options = [
  PDO::MYSQL_ATTR_FOUND_ROWS => true];
Copier après la connexion

MySQLi

$mysqli->info;
Copier après la connexion

Cela affichera les informations de la chaîne entière, telles que :

Rows matched: 1 Changed: 0 Warnings: 0
Copier après la connexion

Vous pouvez le faire

preg_match_all('/(\S[^:]+): (\d+)/', $mysqli->info, $matches); 
$infoArr = array_combine ($matches[1], $matches[2]);
var_export($infoArr);
Copier après la connexion

Ces valeurs sont désormais facilement accessibles. Notez que la valeur est une chaîne, vous pouvez donc convertir toutes les valeurs en int, === fonctionnera, ou vous pouvez vérifier strictement ==.

['Rows matched' => '1', 'Changed' => '0', 'Warnings' => '0']
Copier après la connexion

Récupérer

Obtenir un tableau associatif

PDO

$stmt = $pdo->prepare("SELECT * FROM myTable WHERE id <= ?");
$stmt->execute([5]);
$arr = $stmt->fetchAll(PDO::FETCH_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copier après la connexion

MySQLi

$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->bind_param("s", $_POST[&#39;name&#39;]);
$stmt->execute();
$arr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copier après la connexion

Obtenir une seule ligne

PDO

$stmt = $pdo->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->execute([$_POST[&#39;name&#39;]]);
$arr = $stmt->fetch(PDO::FETCH_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copier après la connexion

MySQLi

$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->bind_param("s", $_POST[&#39;name&#39;]);
$stmt->execute();
$arr = $stmt->get_result()->fetch_assoc();
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copier après la connexion

Obtenir une seule valeur (scalaire)

PDO

$stmt = $pdo->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->execute([$_POST[&#39;name&#39;]]);
$arr = $stmt->fetch(PDO::FETCH_COLUMN);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copier après la connexion

MySQLi

$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->bind_param("s", $_POST[&#39;name&#39;]);
$stmt->execute();
$arr = $stmt->get_result()->fetch_row()[0];
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copier après la connexion

Obtenir un tableau d'objets

PDO

class myClass {}
$stmt = $pdo->prepare("SELECT name, age, weight FROM myTable WHERE name = ?");
$stmt->execute([&#39;Joe&#39;]);
$arr = $stmt->fetchAll(PDO::FETCH_CLASS, &#39;myClass&#39;);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copier après la connexion

MySQLi

class myClass {}
$arr = [];
$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE id = ?");
$stmt->bind_param("s", $_SESSION[&#39;id&#39;]);
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_object(&#39;myClass&#39;)) {
  $arr[] = $row;
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copier après la connexion

正如你所看到的,PDO在这里非常出色。MySQLi没有像$mysqli_result->fetch_all(MYSQLI_OBJ)这样的东西。PDO甚至更进一步,通过使用fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'myClass')对它进行位元化,以处理在类构造函数之后调用它的默认行为。可以在MySQLi中复制这种行为,但是它依赖于省略构造函数,和魔术方法 _set(),或者只在构造函数中设置它(如果它不等于默认值)。

PDO

$search = "%{$_POST[&#39;search&#39;]}%";
$stmt = $pdo->prepare("SELECT id, name, age FROM myTable WHERE name LIKE ?");
$stmt->execute([$search]);
$arr = $stmt->fetchAll();
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy
Copier après la connexion

MySQLi

$search = "%{$_POST[&#39;search&#39;]}%";
$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE name LIKE ?"); 
$stmt->bind_param("s", $search);
$stmt->execute();
$arr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copier après la connexion

获取模式

到目前为止,这是我最喜欢的PDO特性。PDO中的获取模式非常有用,而MySQLi还没有添加它们。

获取键/值对

PDO

$stmt = $pdo->prepare("SELECT event_name, location FROM events WHERE id < ?");
$stmt->execute([25]);
$arr = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy
Copier après la connexion

MySQLi

$arr = [];
$id = 25;
$stmt = $con->prepare("SELECT event_name, location FROM events WHERE id < ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_row()) {
  $arr[$row[0]] = $row[1];
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copier après la connexion

输出:

[&#39;Cool Event&#39; => &#39;Seattle&#39;, &#39;Fun Event&#39; => &#39;Dallas&#39;, &#39;Boring Event&#39; => &#39;Chicago&#39;]
Copier après la connexion

获取组列

PDO

$stmt = $pdo->prepare("SELECT hair_color, name FROM myTable WHERE id < ?");
$stmt->execute([10]);
$arr = $stmt->fetchAll(PDO::FETCH_GROUP | PDO::FETCH_COLUMN);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy
Copier après la connexion

MySQLi

$arr = [];
$id = 10;
$stmt = $con->prepare("SELECT hair_color, name FROM myTable WHERE id < ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_row()) {
  $arr[$row[0]][] = $row[1];
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copy
Copier après la connexion

输出:

[
  &#39;blonde&#39; => [&#39;Patrick&#39;, &#39;Olivia&#39;],
  &#39;brunette&#39; => [&#39;Kyle&#39;, &#39;Ricky&#39;],
  &#39;red&#39; => [&#39;Jordan&#39;, &#39;Eric&#39;]
]
Copier après la connexion

获取键/值对数组

PDO

$stmt = $pdo->prepare("SELECT id, max_bench, max_squat FROM myTable WHERE weight < ?");
$stmt->execute([200]);
$arr = $stmt->fetchAll(PDO::FETCH_UNIQUE);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy
Copier après la connexion

MySQLi

$arr = [];
$weight = 200;
$stmt = $con->prepare("SELECT id, max_bench, max_squat FROM myTable WHERE weight < ?");
$stmt->bind_param("i", $weight);
$stmt->execute();
$result = $stmt->get_result();
$firstColName = $result->fetch_field_direct(0)->name;
while($row = $stmtResult->fetch_assoc()) {
  $firstColVal = $row[$firstColName];
  unset($row[$firstColName]);
  $arr[$firstColVal] = $row;
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copy
Copier après la connexion

输出:

[
  17 => [&#39;max_bench&#39; => 230, &#39;max_squat&#39; => 175],
  84 => [&#39;max_bench&#39; => 195, &#39;max_squat&#39; => 235],
  136 => [&#39;max_bench&#39; => 135, &#39;max_squat&#39; => 285]
]
Copier après la connexion

获取组

PDO

$stmt = $pdo->prepare("SELECT hair_color, name, age FROM myTable WHERE id < ?");
$stmt->execute([12]);
$arr = $stmt->fetchAll(PDO::FETCH_GROUP);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy
Copier après la connexion

MySQLi

$arr = [];
$id = 12;
$stmt = $con->prepare("SELECT hair_color, name, age FROM myTable WHERE id < ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
$firstColName = $result->fetch_field_direct(0)->name;
while($row = $stmtResult->fetch_assoc()) {
  $firstColVal = $row[$firstColName];
  unset($row[$firstColName]);
  $arr[$firstColVal][] = $row;
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copy
Copier après la connexion

输出:

[
  &#39;blonde&#39; => [
    [&#39;name&#39; => &#39;Patrick&#39;, &#39;age&#39; => 22],
    [&#39;name&#39; => &#39;Olivia&#39;, &#39;age&#39; => 18]
  ],
  &#39;brunette&#39;  => [
    [&#39;name&#39; => &#39;Kyle&#39;, &#39;age&#39;=> 25],
    [&#39;name&#39; => &#39;Ricky&#39;, &#39;age&#39; => 34]
  ],
   &#39;red&#39;  => [
    [&#39;name&#39; => &#39;Jordan&#39;, &#39;age&#39; => 17],
    [&#39;name&#39; => &#39;Eric&#39;, &#39;age&#39; => 52]
  ]
]
Copier après la connexion

在数组中的位置

PDO

$inArr = [1, 3, 5];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;)); 
$stmt = $pdo->prepare("SELECT * FROM myTable WHERE id IN ($clause)");
$stmt->execute($inArr);
$resArr = $stmt->fetchAll();
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt = null;
Copy
Copier après la connexion

MySQLi

$inArr = [12, 23, 44];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;)); /
$types = str_repeat(&#39;i&#39;, count($inArr)); /
$stmt = $mysqli->prepare("SELECT id, name FROM myTable WHERE id IN ($clause)");
$stmt->bind_param($types, ...$inArr);
$stmt->execute();
$resArr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt->close();
Copier après la connexion

与其他占位符一起排列的位置

PDO

$inArr = [1, 3, 5];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;)); 
$stmt = $pdo->prepare("SELECT * FROM myTable WHERE id IN ($clause) AND id < ?");
$fullArr = array_merge($inArr, [5]); 
$stmt->execute($fullArr);
$resArr = $stmt->fetchAll();
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt = null;
Copy
Copier après la connexion

MySQLi

$inArr = [12, 23, 44];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;));
$types = str_repeat(&#39;i&#39;, count($inArr));
$types .= &#39;i&#39;; //add 1 more int type
$fullArr = array_merge($inArr, [26]); 
$stmt = $mysqli->prepare("SELECT id, name FROM myTable WHERE id IN ($clause) AND age > ?");
$stmt->bind_param($types, ...$fullArr); 
$stmt->execute();
$resArr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt->close();
Copier après la connexion

交易

PDO

try {
  $pdo->beginTransaction();
  $stmt1 = $pdo->prepare("INSERT INTO myTable (name, state) VALUES (?, ?)");
  $stmt2 = $pdo->prepare("UPDATE myTable SET age = ? WHERE id = ?");
  if(!$stmt1->execute([&#39;Rick&#39;, &#39;NY&#39;])) throw new Exception(&#39;Stmt 1 Failed&#39;);
  else if(!$stmt2->execute([27, 139])) throw new Exception(&#39;Stmt 2 Failed&#39;);
  $stmt1 = null;
  $stmt2 = null;
  $pdo->commit();
} catch(Exception $e) {
  $pdo->rollback();
  throw $e;
}
Copier après la connexion

MySQLi

try {
  $mysqli->autocommit(FALSE);
  $stmt1 = $mysqli->prepare("INSERT INTO myTable (name, age) VALUES (?, ?)");
  $stmt2 = $mysqli->prepare("UPDATE myTable SET name = ? WHERE id = ?");
  $stmt1->bind_param("si", $_POST[&#39;name&#39;], $_POST[&#39;age&#39;]);
  $stmt2->bind_param("si", $_POST[&#39;name&#39;], $_SESSION[&#39;id&#39;]);
  $stmt1->execute();
  $stmt2->execute();
  $stmt1->close();
  $stmt2->close();
  $mysqli->autocommit(TRUE);
} catch(Exception $e) {
  $mysqli->rollback(); 
  throw $e;
}
Copier après la connexion

MySQLi有一个问题,但是解决方案是使用全局处理程序将错误转换为异常。

命名为Paramters

$stmt = $pdo->prepare("UPDATE myTable SET name = :name WHERE id = :id");
$stmt->execute([&#39;:name&#39; => &#39;David&#39;, &#39;:id&#39; => 3]);
$stmt = null;
Copier après la connexion

相关推荐:《mysql教程》《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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal