Heim  >  Artikel  >  Backend-Entwicklung  >  PDO vs. MySQLi: Der Kampf der PHP-Datenbank-APIs

PDO vs. MySQLi: Der Kampf der PHP-Datenbank-APIs

藏色散人
藏色散人Original
2019-03-22 10:56:302815Durchsuche

PDO vs. MySQLi: Der Kampf der PHP-Datenbank-APIs

Einführung

Die Tage der Verwendung der Erweiterung mysql_ sind vorbei, seit PHP 5.5 Seine Methoden sind ab PHP 7 veraltet und wurden entfernt. Aber das Internet ist immer noch voll von alten Tutorials, die Anfänger einfach kopieren/einfügen und mit älteren PHP-Versionen auf Shared-Hosting-Plattformen verwenden können.

Wenn Sie MySQL oder MariaDB in PHP verwenden, haben Sie jetzt die Möglichkeit, MySQLi oder PDO zu verwenden. Ersteres ist nur eine verbesserte Version, unterstützt prozedurale und OOP und fügt vorbereitete Anweisungen hinzu, während letzteres eine Abstraktionsschicht ist, die es Ihnen ermöglicht, eine einheitliche API für alle 12 unterstützten Datenbanktreiber zu verwenden. Obwohl MySQL die beliebteste Datenbank in der PHP-Welt ist.

Theoretisch benötigen wir nicht für jeden vorhandenen Datenbanktyp eine herstellerspezifische API, da es viel einfacher ist, nur eine zu verwenden. Obwohl daran sicherlich viel Wahres dran ist, besteht das Problem darin, dass PDO_MYSQL nicht über alle neuesten und besten Funktionen verfügt, die MySQLi bietet. Ich verstehe ehrlich gesagt nicht, warum das so ist, da dies jeden Grund für die Verwendung einer herstellerspezifischen API völlig beseitigen würde. Dennoch kann ich mir vorstellen, dass die meisten Menschen diese zusätzlichen Funktionen nicht benötigen, aber es gibt sicherlich einige, die dies tun.

Vorteile von PDO

1. Nützliche Erfassungsmethoden

2. Ermöglichen Sie die direkte Übergabe von Variablen und Werten

3. Möglichkeit, Variablentypen automatisch zu erkennen (was tatsächlich passiert, ist, dass beim Senden an den Server alles als Zeichenfolge behandelt, aber in den richtigen Typ konvertiert wird. Dies funktioniert zu 100 % in vorbereiteten Anweisungen, hat jedoch in einigen Fällen keine Auswirkung in Randfällen, z. B. im Simulationsmodus)

4. Bietet eine Option zum automatischen Puffern von Ergebnissen mithilfe vorbereiteter Anweisungen

5. Benannte Parameter (obwohl das Ausschalten des Simulationsmodus in PDO nutzlos ist, weil Sie (kann nur einmal den gleichen Namen verwenden)

MySQLi-Vorteile

1. Informationen über betroffene Zeilen abrufen Die Möglichkeit, mehr bereitzustellen Informationen, wie z. B. das Aktualisieren von Zeilen mit demselben Wert (kann im PDO als Konstruktor festgelegt und später nicht geändert werden)

3. Korrekte Methode zum Herunterfahren der Datenbank

4. ok, wenn der Simulationsmodus in PDO aktiviert ist)

5. Beständige Verbindungen verwenden, um automatisch zu löschen

Unterschiede im Code

PDO und MySQLi sind sehr ähnlich, haben aber eine leicht unterschiedliche Syntax. MySQLi folgt der alten PHP-Snake_case-Konvention, während PDO camelCase verwendet. Darüber hinaus werden die Methoden von MySQLi als Objekteigenschaften verwendet, während PDO die traditionelle Syntax für Funktionen verwendet.

Sowohl PDO als auch MySQLi machen die Sache komplizierter, da Sie zwei separate Methoden verwenden müssen, um vorbereitete Anweisungen zu verwenden. Durch PDO entfällt jedoch die Notwendigkeit, dedizierte Bindungsfunktionen zu verwenden.

Zum Beispiel können Sie dies in der herstellerspezifischen PostgreSQL-API tun.

Als Referenz finden Sie hier ein Beispiel für die Durchführung einer „nicht vorbereiteten“ Abfrage, um ein assoziatives Array mit MySQLi und PDO zu erhalten.

$arr = $mysqli->query("SELECT * FROM myTable")->fetch_all(MYSQLI_ASSOC);
rrree

Eigentlich ist es am besten, einen Wrapper, einen Abfrage-Builder oder ORM zu verwenden. Obwohl PDO Werte direkt an die Ausführung binden kann, ist dies immer noch nicht ideal. In der von mir erstellten Klasse können Sie alle Aufrufe verketten und dabei Werte als Parameter-Parameterbindungen übergeben.

$arr = $pdo->query("SELECT * FROM myTable")->fetchAll(PDO::FETCH_ASSOC);

Das gesamte assoziative Array wird jetzt übersichtlicher in einer Variablen gespeichert.

Neue Datenbankverbindung erstellen

PDO

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

MySQLi

$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}

Einfügen, aktualisieren, löschen

PDO

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}

MySQLi

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

Beachten Sie, dass Prepare() und Execute() mithilfe von PDO verknüpft werden können.

Anzahl der betroffenen Zeilen abrufen

PDO

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

MySQLi

$stmt->rowCount();

Neuesten Primärschlüssel einfügen

Beachten Sie, dass beide Methoden die Verbindungsvariable verwenden, nicht $stmt.

PDO

$stmt->affected_rows;

MySQLi

$pdo->lastInsertId();

Übereinstimmende Zeilen abrufen

PDO

Im PDO das Einzige implementieren Dies erreichen Sie, indem Sie es als Verbindungsoption festlegen, wodurch sich das Verhalten von rowCount() ändert. Das bedeutet, dass rowCount() übereinstimmende Zeilen oder geänderte Zeilen für die gesamte Datenbankverbindung zurückgibt, jedoch nicht für beide.

$mysqli->insert_id;

MySQLi

$options = [
  PDO::MYSQL_ATTR_FOUND_ROWS => true];

Dadurch wird die gesamte Informationsfolge wie folgt ausgegeben:

$mysqli->info;

Sie können dies tun

Rows matched: 1 Changed: 0 Warnings: 0

Jetzt können Sie einfach auf diese Werte zugreifen . Beachten Sie, dass der Wert eine Zeichenfolge ist, sodass Sie alle Werte in int umwandeln können.

===

funktioniert, oder Sie können == streng überprüfen.

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

Abrufen

Assoziatives Array abrufen

PDO

['Rows matched' => '1', 'Changed' => '0', 'Warnings' => '0']

MySQLi

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

Eine einzelne Zeile abrufen

PDO

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

MySQLi

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

Einen einzelnen Wert (Skalar) abrufen

PDO

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

MySQLi

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

Array von Objekten abrufen

PDO

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

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

正如你所看到的,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

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

获取模式

到目前为止,这是我最喜欢的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

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

输出:

[&#39;Cool Event&#39; => &#39;Seattle&#39;, &#39;Fun Event&#39; => &#39;Dallas&#39;, &#39;Boring Event&#39; => &#39;Chicago&#39;]

获取组列

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

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

输出:

[
  &#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;]
]

获取键/值对数组

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

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

输出:

[
  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]
]

获取组

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

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

输出:

[
  &#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]
  ]
]

在数组中的位置

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

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

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

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

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

交易

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

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

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;

相关推荐:《mysql教程》《PHP教程

Das obige ist der detaillierte Inhalt vonPDO vs. MySQLi: Der Kampf der PHP-Datenbank-APIs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn