Веб-разработка / [Перевод] PDO vs. MySQLi

в 6:55, , рубрики: mysqli, PDO, pdo api, pdo vs mysqli, php, prepared statements

Веб разработка / [Перевод] PDO vs. MySQLi При обращении к базе данных в PHP, у нас есть два варианта: MySQLi и PDO. Что нужно знать, прежде чем выбрать какой? Различия, поддержка баз данных, стабильность и производительность — это все обсудим в этой статье.

Краткая таблица:

PDO MySQLi
Поддержка баз данных 12 различных драйверов только MySQL
API ООП ООП + процедурный
Соединение Легкое Легкое
Именованные параметры Да Нет
Object mapping Да Да
Prepared Statements
на стороне клиента
Да Нет
Производительность Быстрый Быстрый
Хранимые процедуры Да Да

Соединение

// PDO $pdo = new PDO("mysql:host=localhost;dbname=database", 'username', 'password');   // mysqli, процедурный способ $mysqli = mysqli_connect('localhost','username','password','database');   // mysqli, объектно-ориентированный способ $mysqli = new mysqli('localhost','username','password','database'); 

API

И PDO и MySQLi наделены объектно-ориентированным API, но MySQLi еще и процедурным API — что делает его легче для новичков. Если вы уже знакомы с драйвером PHP MySQL, то перейти в процедурный интерфейс MySQLi вам будет гораздо проще. А вы мастер PDO, то можете использовать его с любой базой данных как хотите!

Поддержка баз данных

Веб разработка / [Перевод] PDO vs. MySQLi

Основным преимуществом PDO над MySQLi является поддержка множества драйверов баз данных.
На момент написания этой статьи PDO поддерживает 12 различных драйверов, а MySQLi всего один — MySQL.

Для вывода списка всех драйверов которые поддерживает PDO используйте команду:

var_dump(PDO::getAvailableDrivers()); 

Именованные параметры

Это еще одна важная особенность которая имеет PDO, использовать именованные параметры значительно легче, чем цифровые(последовательные):

$params = array(':username' => 'test', ':email' => $mail, ':last_login' => time() - 3600);   $pdo->prepare('    SELECT * FROM users    WHERE username = :username    AND email = :email    AND last_login > :last_login');   $pdo->execute($params); 

А вот MySQLi:

$query = $mysqli->prepare('    SELECT * FROM users    WHERE username = ?    AND email = ?    AND last_login > ?');   $query->bind_param('sss', 'test', $mail, time() - 3600); $query->execute(); 

Знак вопроса, как параметр в MySQLi, может показаться коротким, но это не так хорошо, как именной параметр в связи с тем, что разработчик всегда должен следить за порядком переданных значений.
К сожалению, MySQLi не поддерживает именованные параметры.

Object Mapping

PDO и MySQLi могут сопоставить результаты объекты. Это очень удобно если вы не хотите использовать собственный уровень абстракции базы данных, но хотите ORM-подобное поведение.
Давайте представим что у нас есть класс User с некоторыми свойствами, которые соответствуют именам полей из базы данных.

class User {    public $id;    public $first_name;    public $last_name;      public function info()    {       return '#'.$this->id.': '.$this->first_name.' '.$this->last_name;    } } 

Без объекта отображения мы должны были бы заполнить значение каждого поля (вручную или с помощью конструктора) прежде, чем вызывать info().
Это позволяет заранее определить эти свойства, прежде чем объект будет построен! Например:

$query = "SELECT id, first_name, last_name FROM users";   // PDO $result = $pdo->query($query); $result->setFetchMode(PDO::FETCH_CLASS, 'User');   while ($user = $result->fetch()) {    echo $user->info()."n"; } // MySQLI, процедурный способ if ($result = mysqli_query($mysqli, $query)) {    while ($user = mysqli_fetch_object($result, 'User')) {       echo $user->info()."n";    } } // MySQLi, объектно-ориентированный способ if ($result = $mysqli->query($query)) {    while ($user = $result->fetch_object('User')) {       echo $user->info()."n";    } } 

Безопасность

Веб разработка / [Перевод] PDO vs. MySQLi

Обе библиотеки обеспечивают защиту от SQL инъекций если разработчик использует их правильно (читай: экранировать кавычки).

Допустим, хакер пытается внедрить некоторые вредоносные SQL запросы через GET параметр:

$_GET['username'] = "'; DELETE FROM users; /*"; 

Если нам не удастся избежать этого, он будет включен в запрос «как есть» — удалит всех строк из таблицы пользователей (как PDO так и MySQLi поддержка несколько запросов сразу).

// PDO $username = PDO::quote($_GET['username']);   $pdo->query("SELECT * FROM users WHERE username = $username");   // mysqli $username = mysqli_real_escape_string($_GET['username']);   $mysqli->query("SELECT * FROM users WHERE username = '$username'"); 

Как видите, PDO::quote() не только экранирует строку, но и ставит кавычки, а mysqli_real_escape_string() только экранирует — кавычки надо ставить вручную.

// PDO, prepared statement $pdo->prepare('SELECT * FROM users WHERE username = :username'); $pdo->execute(array(':username' => $_GET['username']));   // mysqli, prepared statements $query = $mysqli->prepare('SELECT * FROM users WHERE username = ?'); $query->bind_param('s', $_GET['username']); $query->execute(); 

Я рекомендую всегда использовать prepared statements, заместо PDO::quote() и mysqli_real_escape_string()

Производительность

PDO и MySQLi оба работают довольно быстро, хотя MySQLi незначительно быстрее в тестах — ~ 2,5% для non-prepared statements и ~ 6,5% для prepared statements.
Тем не менее, родное расширения MySQL быстрее, чем эти оба. Так что если вы действительно должны выжать все до последнего бита производительности, то задумайтесь.

Итог

PDO выигрывает эту битву с легкостью. Благодаря поддержке двенадцати различных драйверов баз данных (восемнадцать различных баз данных!) и именным параметрам, мы можем игнорировать небольшие потери производительности и привыкнуть к его API.
С точки зрения безопасности они оба хороши если разработчик использует их так, как они должны быть использованы.

Если вы все еще работаете с MySQLi, возможно, пришло время для перемен!

Автор: Isis

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js