() translation by (you can also view the original English article)
Når du åbner en database i PHP, vi har to valg: MySQLi og PDO. Så hvad bør du vide før du vælger en? Forskelle, database support, stabilitet og ydeevne bekymringer vil blive beskrevet i denne artikel.
Resume
PDO | MySQLi | |
Database support | 12 forskellige | kun MySQL |
API | OOP | OOP + Procedural |
Forbindelse | Nem | Nem |
Navngivne parametre | Ja | Nej |
Objektet kortlægning | Ja | Ja |
Prepared statements (klientside) |
Ja | Nej |
Ydeevne | Hurtig | Hurtig |
Lagrede procedurer | Ja | Ja |
Forbindelse
Det er nemt at oprette forbindelse til en database med begge:
1 |
// PDO
|
2 |
$pdo = new PDO("mysql:host=localhost;dbname=database", 'username', 'password'); |
3 |
|
4 |
// mysqli, procedural way
|
5 |
$mysqli = mysqli_connect('localhost','username','password','database'); |
6 |
|
7 |
// mysqli, object oriented way
|
8 |
$mysqli = new mysqli('localhost','username','password','database'); |
Bemærk, at disse connection-objekter / ressourcer vil blive betragtet som at eksisterene gennem resten af dette selvstudium.
API Support
Både PDO og MySQLi tilbyder en objektorienteret API, men MySQLi tilbyder også en proceduremæssig API - hvilket gør det nemmere for nybegyndere at forstå. Hvis du er fortrolig med den indfødte PHP MySQL-driver, vil du finde migration til grænsefladen proceduremæssige MySQLi meget lettere. På den anden side, når du mestrer PDO, kan du bruge det med enhver database, du har lyst!
Database support
Den centrale fordel af PDO over MySQLi er i sin database understøttelse. På tidspunktet dette skrives understøtter PDO 12 forskellige drivere, i modsætning til MySQLi, som kun understøtter MySQL.
Hvis du vil udskrive en liste med alle drivere PDO understøtter i øjeblikket, Brug den følgende kode:
1 |
var_dump(PDO::getAvailableDrivers()); |
Hvad betyder det? Nå, i situationer gør når du skal skifte dit projekt for at bruge en anden database, PDO processen gennemsigtig. Så alt du skal gøre er at ændre, forbindelsesstrengen og et par forespørgsler - hvis du bruger nogen metoder, der ikke understøttes af din nye database. Med MySQLi, vil du nødt til at omskrive hver bid af kode - forespørgsler inkluderet.
Navngivet Parametre
Dette er en anden vigtig funktion, at PDO har; bindende parametre er betydeligt lettere end at bruge de numeriske bindende:
1 |
$params = array(':username' => 'test', ':email' => $mail, ':last_login' => time() - 3600); |
2 |
|
3 |
$pdo->prepare(' |
4 |
SELECT * FROM users
|
5 |
WHERE username = :username
|
6 |
AND email = :email
|
7 |
AND last_login > :last_login'); |
8 |
|
9 |
$pdo->execute($params); |
.. .opposed til MySQLi måde:
1 |
$query = $mysqli->prepare(' |
2 |
SELECT * FROM users
|
3 |
WHERE username = ?
|
4 |
AND email = ?
|
5 |
AND last_login > ?'); |
6 |
|
7 |
$query->bind_param('sss', 'test', $mail, time() - 3600); |
8 |
$query->execute(); |
Spørgsmålstegnet parameter bindende virke kortere, men det er ikke næsten så fleksible som navngivne parametre, at udvikleren skal altid holde styr på parameter rækkefølgen; det føles "hacky" under nogle omstændigheder.
Desværre understøtter MySQLi ikke navngivne parametre.
Objektet kortlægning
Både PDO og MySQLi kan knytte resultater til objekter. Dette kommer praktisk, hvis du ikke ønsker at bruge en brugerdefineret database abstraktionslag, men stadig ønsker ORM-lignende adfærd. Lad os forestille os, at vi har en bruger
klasse med nogle egenskaber, som svarer til feltnavnene fra en database.
1 |
class User { |
2 |
public $id; |
3 |
public $first_name; |
4 |
public $last_name; |
5 |
|
6 |
public function info() |
7 |
{
|
8 |
return '#'.$this->id.': '.$this->first_name.' '.$this->last_name; |
9 |
}
|
10 |
}
|
Uden objekt kortlægning, ville vi skulle fylde hvert felts værdi (enten manuelt eller gennem konstruktøren) før vi kan bruge metoden info()
korrekt.
Dette tillader os at foruddefinere disse egenskaber, før objektet er endda bygget! For isntance:
1 |
$query = "SELECT id, first_name, last_name FROM users"; |
2 |
|
3 |
// PDO
|
4 |
$result = $pdo->query($query); |
5 |
$result->setFetchMode(PDO::FETCH_CLASS, 'User'); |
6 |
|
7 |
while ($user = $result->fetch()) { |
8 |
echo $user->info()."\n"; |
9 |
}
|
10 |
// MySQLI, procedural way
|
11 |
if ($result = mysqli_query($mysqli, $query)) { |
12 |
while ($user = mysqli_fetch_object($result, 'User')) { |
13 |
echo $user->info()."\n"; |
14 |
}
|
15 |
}
|
16 |
// MySQLi, object oriented way
|
17 |
if ($result = $mysqli->query($query)) { |
18 |
while ($user = $result->fetch_object('User')) { |
19 |
echo $user->info()."\n"; |
20 |
}
|
21 |
}
|
Sikkerhed
Begge biblioteker giver SQL injektion sikkerhed, så længe udvikleren bruger dem, på den måde, der er bestemt (Læs: undslippe / parameter bindende med udarbejdet udtalelser).
Lad os sige en hacker forsøger at injicere nogle ondsindede SQL gennem 'username' HTTP forespørgslen parameter (GET):
1 |
$_GET['username'] = "'; DELETE FROM users; /*" |
Hvis det ikke lykkes at undslippe dette, vil det være inkluderet i forespørgslen "som er" - slette alle rækker fra tabellen brugere
(både PDO og MySQLi støtte flere forespørgsler).
1 |
// PDO, "manual" escaping
|
2 |
$username = PDO::quote($_GET['username']); |
3 |
|
4 |
$pdo->query("SELECT * FROM users WHERE username = $username"); |
5 |
|
6 |
// mysqli, "manual" escaping
|
7 |
$username = mysqli_real_escape_string($_GET['username']); |
8 |
|
9 |
$mysqli->query("SELECT * FROM users WHERE username = '$username'"); |
Som du kan se, PDO::quote()
ikke kun undslipper strengen, men det også citerer det. På anden siden, vil mysqli_real_escape_string()
kun undslippe streng; Du skal anvende citater manuelt.
1 |
// PDO, prepared statement
|
2 |
$pdo->prepare('SELECT * FROM users WHERE username = :username'); |
3 |
$pdo->execute(array(':username' => $_GET['username'])); |
4 |
|
5 |
// mysqli, prepared statements
|
6 |
$query = $mysqli->prepare('SELECT * FROM users WHERE username = ?'); |
7 |
$query->bind_param('s', $_GET['username']); |
8 |
$query->execute(); |
Jeg anbefaler, at du altid bruger prepared sætninger med bundne forespørgsler i stedet for
PDO::quote()
ogmysqli_real_escape_string()
.
Ydeevne
Mens både PDO og MySQLi er ganske hurtig, MySQLi er utorlig hurtigere i benchmark - ~2.5% for ikke-prepared erklæringer og ~6.5% for prepared dem. Stadig, native MySQL udvidelse er endnu hurtigere end begge disse. Så hvis du virkelig har brug at presse hver sidste smule af ydeevne, der er én ting du måske overveje.
Resume
I sidste ende, PDO vinder denne kamp med lethed. Med understøttelse af tolv forskellige databasedrivere (atter forskellige databaser!) og navngivne parametre, kan vi ignorere det lille performance tab og vænne sig til en API. Fra en sikkerheds synspunkt, begge af dem er sikkert så længe udvikleren bruger dem som de formodes at være brugt (Læs: udarbejdet udtalelser).
Så hvis du stadig arbejder med MySQLi, er måske det tid til en forandring!