{"id":3818,"date":"2014-11-25T10:34:07","date_gmt":"2014-11-25T12:34:07","guid":{"rendered":"http:\/\/blog.turbosite.com.br\/?p=3818"},"modified":"2014-11-25T10:34:07","modified_gmt":"2014-11-25T12:34:07","slug":"pdo-ou-mysqli-qual-usar","status":"publish","type":"post","link":"https:\/\/www.turbosite.com.br\/blog\/pdo-ou-mysqli-qual-usar\/","title":{"rendered":"PDO ou MySQLi, qual usar?"},"content":{"rendered":"<p>A <strong>PHP<\/strong> j\u00e1 anunciou o descontinuamento da\u00a0extens\u00e3o original do <strong>MySQL<\/strong>, nomeando-a como <a href=\"http:\/\/php.net\/manual\/en\/migration55.deprecated.php\">obsoleta<\/a>\u00a0e j\u00e1 com planos para deslig\u00e1-la completamente em vers\u00f5es futuras. A partir da vers\u00e3o <strong>PHP 5.5<\/strong>, tentativas de conex\u00e3o e execu\u00e7\u00e3o de querys com a antiga ferramenta ir\u00e1 gerar mensagens de alerta, denunciando\u00a0que o m\u00e9todo est\u00e1 obsoleto. A antiga forma de conex\u00e3o com o MySQL \u00a0j\u00e1 est\u00e1 a\u00a0caminho de deixar de existir.<\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #ff0000;\"><em>Deprecated: The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead<\/em><\/span><\/p>\n<p>Querendo ou n\u00e3o, o desligamento da antiga ferramenta MySQL \u00e9 inevit\u00e1vel.\u00a0Sem d\u00favida, o trabalho para conseguir migrar todas as fun\u00e7\u00f5es de conex\u00e3o com o MySQL para uma outra ferramenta, em provavelmente grande parte de seus projetos, vai ser custosa e demorada.\u00a0Por\u00e9m, \u00e9 muito prov\u00e1vel que seus esfor\u00e7os ser\u00e3o recompensados.\u00a0Em seu site, a PHP nos indica duas ferramentas de conex\u00e3o com o MySQL: a MySQLi (Improved) e o PDO.<\/p>\n<p style=\"padding-left: 30px;\"><em>A <a href=\"http:\/\/php.net\/manual\/en\/book.mysql.php\">extens\u00e3o original MySQL<\/a> est\u00e1 agora obsoleta e ir\u00e1 gerar erros <strong>E_DEPRECATED<\/strong> quando conectar \u00e0 um banco de dados. Em seu lugar, use a\u00a0extens\u00e3o\u00a0<a href=\"http:\/\/php.net\/manual\/en\/book.mysqli.php\">MySQLi<\/a> ou <a href=\"http:\/\/php.net\/manual\/en\/ref.pdo-mysql.php\">PDO MySQL<\/a>.<\/em><\/p>\n<p>A equipe da <a href=\"https:\/\/www.turbosite.com.br\/\">Turbosite<\/a>\u00a0retirou do blog <a href=\"http:\/\/code.tutsplus.com\/pt\/tutorials\/pdo-vs-mysqli-which-should-you-use--net-24059\">Code<\/a>\u00a0um artigo que explica em detalhes o funcionamento e as diferen\u00e7as de cada ferramenta. Detalhando c\u00f3digo para conex\u00e3o, querys, detalhes de seguran\u00e7a e desempenho. Abaixo voc\u00ea confere as diferen\u00e7as entre essas duas ferramentas.<\/p>\n<p>&nbsp;<\/p>\n<h2>Comparativo<\/h2>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>PDO<\/th>\n<th>MySQLi<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Suporte a Bancos de Dados<\/strong><\/td>\n<td>12 drivers diferentes<\/td>\n<td>Somente MySQL<\/td>\n<\/tr>\n<tr>\n<td><strong>API<\/strong><\/td>\n<td>Orientada a Objetos<\/td>\n<td>Orientada a Objetos + Procedural<\/td>\n<\/tr>\n<tr>\n<td><strong>Conex\u00e3o<\/strong><\/td>\n<td>F\u00e1cil<\/td>\n<td>F\u00e1cil<\/td>\n<\/tr>\n<tr>\n<td><strong>Par\u00e2metros Nomeados<\/strong><\/td>\n<td>Sim<\/td>\n<td>N\u00e3o<\/td>\n<\/tr>\n<tr>\n<td><strong>Mapeamento de Objetos<\/strong><\/td>\n<td>Sim<\/td>\n<td>Sim<\/td>\n<\/tr>\n<tr>\n<td><strong>Senten\u00e7as Preparadas (lado do cliente)<\/strong><\/td>\n<td>Sim<\/td>\n<td>N\u00e3o<\/td>\n<\/tr>\n<tr>\n<td><strong>Performance<\/strong><\/td>\n<td>R\u00e1pido<\/td>\n<td>R\u00e1pido<\/td>\n<\/tr>\n<tr>\n<td><strong>Procedimentos Armazenados<\/strong><\/td>\n<td>Sim<\/td>\n<td>Sim<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Conex\u00e3o<\/h2>\n<p>Criar uma conex\u00e3o com uma base de dados \u00e9 f\u00e1cil\u00a0em\u00a0ambas as ferramentas:<\/p>\n<pre class=\"lang:php decode:true \">\/\/ PDO\n$pdo = new PDO(\"mysql:host=servidor;dbname=banco_de_dados\", 'usuario', 'senha');\n  \n\/\/ MySQLi, forma procedural\n$mysqli = mysqli_connect('servidor', 'usuario', 'senha', 'banco_de_dados');\n  \n\/\/ MySQLi, forma via orienta\u00e7\u00e3o a objetos\n$mysqli = new mysqli('servidor', 'usuario', 'senha', 'banco_de_dados');\n<\/pre>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Suporte de API<\/h2>\n<p>Tanto PDO quanto MySQli oferecem um API orientada a objetos, mas o MySQLi tamb\u00e9m oferece uma API procedural &#8211; facilitando o entendimento por parte dos novatos. Se voc\u00ea j\u00e1 \u00e9 familiarizado com o driver nativo do MySQL para PHP, migrar para a interface procedural do MySQLi ser\u00e1 extremamente simples. Por outro lado, uma vez que voc\u00ea compreender a PDO, voc\u00ea poder\u00e1 us\u00e1-la com qualquer banco de dados que desejar!<\/p>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Suporte a Bancos de Dados<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-3819 alignnone\" src=\"https:\/\/www.turbosite.com.br\/blog\/wp-content\/uploads\/2014\/11\/tutorial_3.png\" alt=\"tutorial_3\" width=\"640\" height=\"320\" srcset=\"https:\/\/www.turbosite.com.br\/blog\/wp-content\/uploads\/2014\/11\/tutorial_3.png 640w, https:\/\/www.turbosite.com.br\/blog\/wp-content\/uploads\/2014\/11\/tutorial_3-300x150.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>A principal vantagem do PDO sobre o MySQLi \u00e9 seu suporte aos drivers de diversos bancos de dados. No momento em que traduzimos\u00a0esse artigo, o\u00a0<strong>PDO d\u00e1 suporte a 12 tipos diferentes de drivers<\/strong>, enquanto o MySQLi s\u00f3 d\u00e1\u00a0<strong>suporte ao MySQL<\/strong>.<\/p>\n<p>Caso queira saber quais os drivers que o PDO d\u00e1 suporte no momento, use o c\u00f3digo a seguir:<\/p>\n<pre class=\"lang:php decode:true \">var_dump(PDO::getAvailableDrivers());<\/pre>\n<p>O que isso significa? Bem, em situa\u00e7\u00f5es que voc\u00ea precisar usar outro banco de dados, a PDO torna esse processo transparente. Ent\u00e3o,\u00a0<em>a \u00fanica coisa que voc\u00ea precisar\u00e1 fazer<\/em>\u00a0\u00e9 mudar os par\u00e2metros de conex\u00e3o e algumas consultas, isso se elas usarem algum m\u00e9todo que n\u00e3o seja suportado por outra base de dados. J\u00e1 com o MySQLi, voc\u00ea precisar\u00e1\u00a0<em>reescrever todo o c\u00f3digo que lida com banco de dados,\u00a0<\/em>\u00a0inclusive as consultas.<\/p>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Par\u00e2metros Nomeados<\/h2>\n<p>Essa \u00e9 outra caracter\u00edstica importante que o PDO tem. Vincular par\u00e2metros com PDO \u00e9 muito mais f\u00e1cil usando a vincula\u00e7\u00e3o nomeada:<\/p>\n<pre class=\"lang:php decode:true \">$params = [':usuario' =&gt; 'teste', ':email' =&gt; $email =&gt; ':ultimo_login' =&gt; time() - 3600];\n  \n$pdo-&gt;prepare('SELECT * FROM users WHERE username = :usuario AND email = :email AND las_login = :ultimo_login');\n  \n$pdo-&gt;execute($params);<\/pre>\n<p>Ao contr\u00e1rio da maneira do MySQLi:<\/p>\n<pre class=\"lang:php decode:true\">$query = $mysqli-&gt;prepare('SELECT * FROM users WHERE username = ? AND email = ? AND lasT_login = ?');\n  \n$query-&gt;bind_param('teste', $mail, time() - 3600);\n$query-&gt;execute();<\/pre>\n<p>A vincula\u00e7\u00e3o dos par\u00e2metros na forma de interroga\u00e7\u00e3o pode parecer menor, mas, nem de longe, \u00e9 t\u00e3o flex\u00edvel quanto aos par\u00e2metros nomeados, devido ao fato do desenvolvedor ser obrigado a saber a ordem dos par\u00e2metros. Ela parece um\u00a0<em>hack<\/em>\u00a0feito para permitir vincula\u00e7\u00e3o de par\u00e2metros em algumas circunst\u00e2ncias.<\/p>\n<p>Infelizmente,\u00a0<strong>MySQLi n\u00e3o d\u00e1 suporte a par\u00e2metros nomeados<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Mapeamento de Objetos<\/h2>\n<p>Tanto PDO quanto MySQLi podem mapear resultados em objetos. Isso vem bem a calhar se voc\u00ea n\u00e3o quer usar uma camada de abstra\u00e7\u00e3o de banco de dados customizada, mas ainda quer um comportamento semelhante ao de um\u00a0<em>ORM<\/em>. Vamos imaginar que n\u00f3s temos uma classe\u00a0<code>User<\/code>\u00a0com algumas propriedades nomeadas de forma id\u00eantica aos campos da tabela do Banco de Dados:<\/p>\n<pre class=\"lang:php decode:true  \">class User {\npublic $id;\npublic $first_name;\npublic $last_name;\n  \npublic function info()\n{\nreturn \"#\" . $this-&gt;id . \": \" . $this-&gt;first_name . \" \" . $this-&gt;last_name;\n}\n}<\/pre>\n<p>Sem o mapeamento de objetos, n\u00f3s precisar\u00edamos preencher cada um dos campos (fosse manualmente ou atrav\u00e9s de um m\u00e9todo construtor), anes de podermos usar o m\u00e9todo\u00a0<code>info()<\/code>\u00a0corretamente.<\/p>\n<p>Isso permite que n\u00f3s predefinamos as propriedades antes mesmo do objeto ser constru\u00eddo! Por exemplo<\/p>\n<pre class=\"lang:php decode:true\">$query = \"SELECT id, first_name, last_name FROM users\";\n  \n\/\/ PDO\n$result = $pdo-&gt;query($query);\n$result-&gt;setFetchMode(PDO::FETCH_CLASS, 'User');\n  \nwhile ($user = $result-&gt;fetch()) {\necho $user-&gt;info() . \"\\n\";\n}\n  \n\/\/ MySQLi, forma procedural\nif ($result = mysqli_query($mysqli, $query)) {\nwhile ($user = mysqli_fetch_object($result, 'User')) {\necho $user-&gt;info() . \"\\n\";\n}\n}\n  \n\/\/ MySQLi, forma orientada a objetos\nif ($result = $mysqli-&gt;query($query)) {\nwhile ($user = $result-&gt;fetch_object('User')) {\necho $user-&gt;info() . \"\\n\";\n}\n}<\/pre>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Seguran\u00e7a<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-3820 alignnone\" src=\"https:\/\/www.turbosite.com.br\/blog\/wp-content\/uploads\/2014\/11\/tutorial_1.png\" alt=\"tutorial_1\" width=\"640\" height=\"320\" srcset=\"https:\/\/www.turbosite.com.br\/blog\/wp-content\/uploads\/2014\/11\/tutorial_1.png 640w, https:\/\/www.turbosite.com.br\/blog\/wp-content\/uploads\/2014\/11\/tutorial_1-300x150.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>Ambas as bibliotecas proveem\u00a0<strong>seguran\u00e7a contra inje\u00e7\u00e3o de SQL, desde que o desenvolvedor as use da maneira que elas foram planejadas para usar.\u00a0<\/strong>Digamos que um\u00a0<em>hacker<\/em>\u00a0esteja tentando injetar algum c\u00f3digo malicioso atrav\u00e9s de um par\u00e2metro &#8216;username&#8217; de uma requisi\u00e7\u00e3o HTTP GET:<\/p>\n<pre class=\"lang:php decode:true\">$_GET['username'] = \"'; DELETE FROM users; \/*\"<\/pre>\n<p>&nbsp;<\/p>\n<p>Se n\u00f3s falharmos em limp\u00e1-lo, ele ser\u00e1 inclu\u00eddo na consulta exatamente como est\u00e1 \u00a0e deletar\u00e1 todas linhas da tabela\u00a0<code>users<\/code>\u00a0(tanto PDO quanto MySQLi suporta m\u00faltiplas consultas).<\/p>\n<pre class=\"lang:php decode:true \">\/\/ PDO, limpeza manual\n$username = PDO::quote($_GET['username']);\n  \n$pdo-&gt;query(\"SELECT * FROM users WHERE username = $username\");\n  \n\/\/ MySQLi, limpeza manual\n$username = mysqli_real_escape_string($_GET['username']);\n  \n$mysqli-&gt;query(\"SELECT * FROM users WHERE username = '$username'\");<\/pre>\n<p>&nbsp;<\/p>\n<p>Como podem ver,\u00a0<code>PDO::quote()<\/code>\u00a0<strong>n\u00e3o s\u00f3 valida, mas fixa as aspas<\/strong>. Por outro lado,\u00a0<code>mysqli_real_escape_string()<\/code>\u00a0s\u00f3 limpar\u00e1, for\u00e7ando voc\u00ea a fixar as aspas manualmente.<\/p>\n<pre class=\"lang:php decode:true\">\/\/ PDO com senten\u00e7as preparadas\n$pdo-&gt;prepare('SELECT * FROM users WHERE username = :username');\n$pdo-&gt;execute([':username' =&gt; $_GET['username']]);\n  \n\/\/ MySQLi, senten\u00e7as preparadas\n$query = $mysqli-&gt;prepare('SELECT * FROM users WHERE username = ?');\n$query-&gt;bind_param('s', $_GET['username']);\n$query-&gt;execute();<\/pre>\n<p>&nbsp;<\/p>\n<p>Recomendamos que voc\u00ea sempre use senten\u00e7as preparadas com consultas vinculadas ao inv\u00e9s da\u00a0<code>PDO::quote()<\/code>\u00a0e da\u00a0<code>mysqli_real_scape_string()<\/code>.<\/p>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Performance<\/h2>\n<p>Tanto PDO quanto MySQLi s\u00e3o bem r\u00e1pidas, por\u00e9m, MySQLi se sai mais r\u00e1pida nos comparativos; ~2,5% para senten\u00e7as n\u00e3o preparadas e ~6,5% para as senten\u00e7as preparadas. Por\u00e9m, a extens\u00e3o nativa do MySQL \u00e9 ainda mais r\u00e1pida que ambas. Mas, como afirmei no come\u00e7o, ela n\u00e3o \u00e9 mais uma op\u00e7\u00e3o.<\/p>\n<p>&nbsp;<\/p>\n<h2 class=\"nolinks\">Conclus\u00e3o<\/h2>\n<p>PDO possu\u00ed\u00a0suporte a 12 drivers de bases de dados diferentes e par\u00e2metros nomeados. MySQLi ganha em desempenho, comparado com o PDO \u00a0e possui uma sintaxe mais simples, facilitando a migra\u00e7\u00e3o a partir do antigo MySQL. Com rela\u00e7\u00e3o \u00e0 seguran\u00e7a, ambas s\u00e3o seguras, desde que o desenvolvedor saiba us\u00e1-las da forma correta.<\/p>\n<p>Em especial, deixaremos a conclus\u00e3o desse artigo para o leitor. Caso voc\u00ea esteja procurando desempenho em suas querys e n\u00e3o quer esquentar a cabe\u00e7a para aprender uma nova ferramenta de conex\u00e3o com o banco de dados, talvez o <a href=\"http:\/\/php.net\/manual\/pt_BR\/book.mysqli.php\">MySQLi <\/a>seja sua melhor escolha. Caso voc\u00ea esteja procurando uma ferramenta mais completa e robusta, o <a href=\"http:\/\/php.net\/manual\/pt_BR\/ref.pdo-mysql.php\">PDO MySQL<\/a> seria a melhor escolha.<\/p>\n<p>Deixe-nos sua resposta, fa\u00e7a um coment\u00e1rio abaixo falando qual ferramenta voc\u00ea escolheu o por qu\u00ea.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A extens\u00e3o original MySQL do PHP est\u00e1 obsoleta, deixando como escolha o MySQLi e PDO MySQL. Por\u00e9m, qual das duas \u00e9 a melhor escolha? Explicaremos nesse artigo.<\/p>\n","protected":false},"author":1,"featured_media":3821,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,6,19,28],"tags":[433,434,480,485],"class_list":["post-3818","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-desenvolvimento","category-dicas","category-mysql","category-tutoriais","tag-mysql","tag-mysqli","tag-pdo","tag-php"],"_links":{"self":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/posts\/3818","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/comments?post=3818"}],"version-history":[{"count":0,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/posts\/3818\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/media\/3821"}],"wp:attachment":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/media?parent=3818"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/categories?post=3818"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/tags?post=3818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}