PDO vs MySQLi: Mana yang Harus Anda Gunakan?
Indonesian (Bahasa Indonesia) translation by ⚡ Rova Rindrata (you can also view the original English article)
Saat mengakses database di PHP, kita memiliki dua pilihan: MySQLi dan PDO. Jadi apa yang harus Anda ketahui sebelum memilih salah satunya? Masalah kekhawatiran perbedaan, dukungan database, stabilitas dan kinerja akan dibahas dalam artikel ini.
Ringkasan
| PDO | MySQLi | |
| Dukungan database | 12 driver berbeda | Hanya MySQL |
| API | OOP | OOP + prosedural |
| Koneksi | Mudah | Mudah |
| Parameter bernama | Ya | Tidak |
| Pemetaan objek | Ya | Ya |
| Prepared statements (sisi client) |
Ya | Tidak |
| Kinerja | Cepat | Cepat |
| Stored procedures | Ya | Ya |
Koneksi
Sangat mudah untuk terhubung ke database dengan keduanya:
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'); |
Harap dicatat bahwa obyek-obyek koneksi/sumber daya ini akan dianggap selalu ada sampai akhir dari tutorial ini.
Dukungan API
PDO dan MySQLi menawarkan API berorientasi obyek, tapi MySQLi juga menawarkan API prosedural - yang membuatnya lebih mudah dipahami bagi pemula. Jika Anda sudah familiar dengan driver PHP MySQL yang asli, Anda akan menemukan migrasi ke antarmuka MySQLi prosedural jauh lebih mudah. Di sisi lain, setelah Anda menguasai PDO, Anda dapat menggunakannya dengan setiap database yang Anda inginkan!
Dukungan Database



Keuntungan utama dari PDO dari MySQLi adalah dalam dukungannya terhadap driver database. Pada saat penulisan ini, PDO mendukung 12 driver berbeda, berlawanan dengan MySQLi, yang hanya mendukung MySQL.
Untuk mencetak daftar semua driver PDO yang saat ini didukung, gunakan kode berikut:
1 |
var_dump(PDO::getAvailableDrivers()); |
Apa artinya ini? Nah, dalam situasi ketika Anda harus mengalihkan proyek Anda menggunakan database lain, PDO membuat proses menjadi transparan. Jadi yang hanya harus Anda lakukan adalah perubahan koneksi string dan beberapa query - jika mereka menggunakan metode yang tidak didukung oleh database baru Anda. Dengan MySQLi, Anda akan perlu untuk menulis ulang setiap potongan kode - termasuk query.
Parameter Bernama
Ini adalah fitur penting lain yang memiliki PDO; mengikat parameter jauh lebih mudah daripada menggunakan pengikatan angka:
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); |
...berlawanan dengan cara MySQLi:
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(); |
Pengikatan parameter tanda tanya mungkin tampak lebih pendek, tetapi tidak hampir sefleksibel parameter bernama, karena fakta bahwa pengembang harus selalu melacak urutan parameter; rasanya "hacky" dalam beberapa keadaan.
Sayangnya, MySQLi tidak mendukung parameter bernama.
Pemetaan Objek
PDO dan MySQLi dapat memetakan hasil dalam bentuk obyek. Hal ini sangat berguna jika Anda tidak ingin menggunakan lapisan abstraksi database kustom, tapi masih ingin perilaku seperti-ORM. Mari kita bayangkan bahwa kita memiliki class User dengan beberapa properti, yang cocok dengan nama field dari 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 |
}
|
Tanpa pemetaan obyek, kita perlu untuk mengisi setiap nilai field (baik secara manual atau melalui konstruktor) sebelum kita dapat menggunakan metode info() dengan benar.
Hal ini memungkinkan kita untuk menentukan properti dahulu bahkan sebelum obyek dibangun! Misalnya:
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 |
}
|
Keamanan



Kedua library menyediakan keamanan injeksi SQL, asalkan pengembang menggunakan mereka dengan cara yang mereka maksudkan (baca: escaping / parameter yang mengikat dengan prepared statements).
Misalnya seorang hacker mencoba untuk menyuntikkan beberapa SQL berbahaya melalui parameter query HTTP 'username' (GET):
1 |
$_GET['username'] = "'; DELETE FROM users; /*" |
Jika kita gagal untuk meng-escape ini, maka akan disertakan dalam pencarian "sebagaimana adanya" - menghapus semua baris dari tabel users (PDO dan mysqli mendukung beberapa query).
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'"); |
Seperti yang Anda lihat, PDO::quote() tidak hanya meng-escape string, tetapi juga meng-quote-nya. Di sisi lain, mysqli_real_escape_string() hanya akan meng-escape string, Anda akan perlu untuk menerapkan quote secara manual.
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(); |
Saya sarankan bahwa Anda selalu menggunakan prepared statements dengan query terikat daripada
PDO::quote()danmysqli_real_escape_string().
Kinerja
Sementara PDO dan MySQLi cukup cepat, MySQLi tanpa signifikan lebih cepat dalam benchmark - ~2.5% untuk non-prepared statements, dan ~6.5% untuk prepared statements. Bagaimanapun juga, ekstensi MySQL asli lebih cepat daripada keduanya. Jadi jika Anda benar-benar perlu untuk memeras kinerja sampai titik terakhir, itu adalah satu hal yang mungkin Anda pertimbangkan.
Ringkasan
Pada akhirnya, PDO memenangkan pertempuran ini dengan mudah. Dengan dukungan untuk dua belas driver database yang berbeda (delapan belas database berbeda!) dan parameter bernama, kita dapat mengabaikan kerugian kecil di kinerja, dan akan terbiasa dengan API-nya. Dari sudut pandang keamanan, keduanya aman asalkan pengembang menggunakan mereka dengan cara yang seharusnya digunakan (baca: prepared statements).
Jadi jika Anda masih bekerja dengan MySQLi, mungkin ini adalah waktu untuk perubahan!



