PDO ou MySQLi, qual usar?

10:34

A PHP já anunciou o descontinuamento da extensão original do MySQL, nomeando-a como obsoleta e já com planos para desligá-la completamente em versões futuras. A partir da versão PHP 5.5, tentativas de conexão e execução de querys com a antiga ferramenta irá gerar mensagens de alerta, denunciando que o método está obsoleto. A antiga forma de conexão com o MySQL  já está a caminho de deixar de existir.

Deprecated: The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead

Querendo ou não, o desligamento da antiga ferramenta MySQL é inevitável. Sem dúvida, o trabalho para conseguir migrar todas as funções de conexão com o MySQL para uma outra ferramenta, em provavelmente grande parte de seus projetos, vai ser custosa e demorada. Porém, é muito provável que seus esforços serão recompensados. Em seu site, a PHP nos indica duas ferramentas de conexão com o MySQL: a MySQLi (Improved) e o PDO.

A extensão original MySQL está agora obsoleta e irá gerar erros E_DEPRECATED quando conectar à um banco de dados. Em seu lugar, use a extensão MySQLi ou PDO MySQL.

A equipe da Turbosite retirou do blog Code um artigo que explica em detalhes o funcionamento e as diferenças de cada ferramenta. Detalhando código para conexão, querys, detalhes de segurança e desempenho. Abaixo você confere as diferenças entre essas duas ferramentas.

 

Comparativo

PDOMySQLi
Suporte a Bancos de Dados12 drivers diferentesSomente MySQL
APIOrientada a ObjetosOrientada a Objetos + Procedural
ConexãoFácilFácil
Parâmetros NomeadosSimNão
Mapeamento de ObjetosSimSim
Sentenças Preparadas (lado do cliente)SimNão
PerformanceRápidoRápido
Procedimentos ArmazenadosSimSim

 

Criar uma conexão com uma base de dados é fácil em ambas as ferramentas:

// PDO$pdo = new PDO("mysql:host=servidor;dbname=banco_de_dados", 'usuario', 'senha'); // MySQLi, forma procedural$mysqli = mysqli_connect('servidor', 'usuario', 'senha', 'banco_de_dados'); // MySQLi, forma via orientação a objetos$mysqli = new mysqli('servidor', 'usuario', 'senha', 'banco_de_dados');

 

Tanto PDO quanto MySQli oferecem um API orientada a objetos, mas o MySQLi também oferece uma API procedural – facilitando o entendimento por parte dos novatos. Se você já é familiarizado com o driver nativo do MySQL para PHP, migrar para a interface procedural do MySQLi será extremamente simples. Por outro lado, uma vez que você compreender a PDO, você poderá usá-la com qualquer banco de dados que desejar!

 

tutorial_3

 

A principal vantagem do PDO sobre o MySQLi é seu suporte aos drivers de diversos bancos de dados. No momento em que traduzimos esse artigo, o PDO dá suporte a 12 tipos diferentes de drivers, enquanto o MySQLi só dá suporte ao MySQL.

Caso queira saber quais os drivers que o PDO dá suporte no momento, use o código a seguir:

var_dump(PDO::getAvailableDrivers());

O que isso significa? Bem, em situações que você precisar usar outro banco de dados, a PDO torna esse processo transparente. Então, a única coisa que você precisará fazer é mudar os parâmetros de conexão e algumas consultas, isso se elas usarem algum método que não seja suportado por outra base de dados. Já com o MySQLi, você precisará reescrever todo o código que lida com banco de dados,  inclusive as consultas.

 

Essa é outra característica importante que o PDO tem. Vincular parâmetros com PDO é muito mais fácil usando a vinculação nomeada:

$params = [':usuario' => 'teste', ':email' => $email => ':ultimo_login' => time() - 3600]; $pdo->prepare('SELECT * FROM users WHERE username = :usuario AND email = :email AND las_login = :ultimo_login'); $pdo->execute($params);

Ao contrário da maneira do MySQLi:

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

A vinculação dos parâmetros na forma de interrogação pode parecer menor, mas, nem de longe, é tão flexível quanto aos parâmetros nomeados, devido ao fato do desenvolvedor ser obrigado a saber a ordem dos parâmetros. Ela parece um hack feito para permitir vinculação de parâmetros em algumas circunstâncias.

Infelizmente, MySQLi não dá suporte a parâmetros nomeados.

 

Tanto PDO quanto MySQLi podem mapear resultados em objetos. Isso vem bem a calhar se você não quer usar uma camada de abstração de banco de dados customizada, mas ainda quer um comportamento semelhante ao de um ORM. Vamos imaginar que nós temos uma classe User com algumas propriedades nomeadas de forma idêntica aos campos da tabela do Banco de Dados:

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

Sem o mapeamento de objetos, nós precisaríamos preencher cada um dos campos (fosse manualmente ou através de um método construtor), anes de podermos usar o método info() corretamente.

Isso permite que nós predefinamos as propriedades antes mesmo do objeto ser construído! Por exemplo

$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, forma proceduralif ($result = mysqli_query($mysqli, $query)) {while ($user = mysqli_fetch_object($result, 'User')) {echo $user->info() . "\n";}} // MySQLi, forma orientada a objetosif ($result = $mysqli->query($query)) {while ($user = $result->fetch_object('User')) {echo $user->info() . "\n";}}

 

tutorial_1

 

Ambas as bibliotecas proveem segurança contra injeção de SQL, desde que o desenvolvedor as use da maneira que elas foram planejadas para usar. Digamos que um hacker esteja tentando injetar algum código malicioso através de um parâmetro ‘username’ de uma requisição HTTP GET:

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

 

Se nós falharmos em limpá-lo, ele será incluído na consulta exatamente como está  e deletará todas linhas da tabela users (tanto PDO quanto MySQLi suporta múltiplas consultas).

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

 

Como podem ver, PDO::quote() não só valida, mas fixa as aspas. Por outro lado, mysqli_real_escape_string() só limpará, forçando você a fixar as aspas manualmente.

// PDO com sentenças preparadas$pdo->prepare('SELECT * FROM users WHERE username = :username');$pdo->execute([':username' => $_GET['username']]); // MySQLi, sentenças preparadas$query = $mysqli->prepare('SELECT * FROM users WHERE username = ?');$query->bind_param('s', $_GET['username']);$query->execute();

 

Recomendamos que você sempre use sentenças preparadas com consultas vinculadas ao invés da PDO::quote() e da mysqli_real_scape_string().

 

Tanto PDO quanto MySQLi são bem rápidas, porém, MySQLi se sai mais rápida nos comparativos; ~2,5% para sentenças não preparadas e ~6,5% para as sentenças preparadas. Porém, a extensão nativa do MySQL é ainda mais rápida que ambas. Mas, como afirmei no começo, ela não é mais uma opção.

 

PDO possuí suporte a 12 drivers de bases de dados diferentes e parâmetros nomeados. MySQLi ganha em desempenho, comparado com o PDO  e possui uma sintaxe mais simples, facilitando a migração a partir do antigo MySQL. Com relação à segurança, ambas são seguras, desde que o desenvolvedor saiba usá-las da forma correta.

Em especial, deixaremos a conclusão desse artigo para o leitor. Caso você esteja procurando desempenho em suas querys e não quer esquentar a cabeça para aprender uma nova ferramenta de conexão com o banco de dados, talvez o MySQLi seja sua melhor escolha. Caso você esteja procurando uma ferramenta mais completa e robusta, o PDO MySQL seria a melhor escolha.

Deixe-nos sua resposta, faça um comentário abaixo falando qual ferramenta você escolheu o por quê.