El otro día, mientras creaba nuevos conceptos para luego convertirlos en tutorial (el último este de aquí), se me presentó una pregunta: ¿es realmente MySQLi la opción correcta para acceder a las bases de datos ahora que MySQL se ha declarado obsoleta a partir de PHP 5.5.0?
Me puse a investigar de inmediato, y hallé dos principales métodos de acceso a bases de datos: la capa de abstracción PDO y la extensión nativa de PHP MySQLi.
Resúmen
En la siguiente tabla se recojen las principales características de las dos librerías.
Característica | PDO | MySQLi |
---|---|---|
Versión PHP donde se introdujo. | 5.1 | 5.0 |
Incluida con PHP 5.x | Sí. | Sí. |
Bases de datos soportadas. | Más de 12. | Solo MySQL. |
Interfaz. | POO. | POO y procedimental. |
Sentencias preparadas (del lado del cliente). | Sí. | No. |
Parámetros con nombre (en sentencias preparadas). | Sí. | No. |
Procedimientos almacenados. | Sí. | Sí. |
Aplicación de datos en objetos. | Sí. | Sí. |
Conexión
Es sencillo realizar la conexión en cualquiera de las dos librerías.
// PDO. $PDO = new PDO( 'mysql:hostname=localhost;dbname=database', 'username', 'password' ); // MySQLi (procedimental). $MySQLi = mysqli_connect( 'localhost', 'username', 'password', 'database' ); // MySQLi (POO). $MySQLi = new MySQLi( 'localhost', 'username', 'password', 'database' );
Como podeis apreciar en PDO el primer parámetro contiene el tipo de base de datos (mysql
) y otros parámetros separados por ;
. Después se especifican el usuario y contraseña. Como parámetro opcional podemos especificar un array
con opciones.
En MySQLi todos los datos se especifican como parámetros separados.
Nota: estas variables estarán presentes en los demás códigos del artículo.
Interfaz
Las dos librerías disponen de una API orientada a objetos, pero además MySQLi ofrece una API procedimental, la cual es más sencilla de aprender para programadores recien iniciados.
Soporte de bases de datos
Mientras que MySQLi solo soporta bases de datos MySQL, PDO tiene una lista más extensa. Para ver los drivers que soporta actualmente PDO solo hay que ejecutar la siguiente línea de código:
var_dump( PDO::getAvailableDrivers() );
Parámetros con nombre
Una gran ventaja en el uso de PDO es que, a la hora de ejecutar sentencias preparadas, los parametros pueden llevar un nombre. Veamos un ejemplo:
$params = array( ':username' => 'username', ':email' => 'email' ); $stmt = $PDO->prepare( 'SELECT * FROM users WHERE username = :username AND email = :email' ); $stmt->execute( $params );
Con MySQLi tendremos que utilizar ?
.
$stmt = $MySQLi->prepare( 'SELECT * FROM users WHERE username = ? AND email = ?' ); $stmt->bind_param( 'ss', 'username', 'email' );
Esta es claramente una desventaja, ya que utilizando la segunda opción deberemos mantener el orden de los parámetros en todo momento.
Aplicación de datos en objetos.
Una de las ventajas que tienen las dos librerías es que pueden obtener directamente los datos de una consulta e inyectarlos en un objeto. Por ejemplo, pongamos que tenemos el siguiente objeto Car
.
class Car { public $manufacturer; public $model; public $weight; }
Si obtenemos los datos de una tabla, podremos inyectarlos y crear diferentes objetos (coches en este caso) directamente:
$sql = 'SELECT manufacturer, model, weight FROM cars'; // PDO. $query = $PDO->query( $sql ); $query->setFetchMode( PDO::FETCH_CLASS, 'Car' ); while ( $car = $query->fetch() ) { var_dump( $car ); } // MySQLi (procedimental). if ( $query = mysqli_query( $MySQLi, $sql ) ) { while ( $car = mysqli_fetch_object( $query, 'Car' ) ) { var_dump( $car ); } } // MySQLi (POO). if ( $query = $MySQLi->query( $query ) ) { while ( $car = $query->fetch_object( 'Car' ) ) { var_dump( $car ); } }
Seguridad
Las dos librerías ofrecen seguridad contra SQL Inyection, siempre y cuando se utilicen en el modo en que están pensadas. Para escapar variables manualmente basta con usar PDO::quote()
en una o mysqli_real_escape_string()
en la otra, aunque se recomienda el uso de sentencias preparadas ya que estas filtran los datos automáticamente.
Redimiento
Siguiendo algunos tests realizados, podemos decir que MySQLi es ligeramente más rapido en consultas del tipo SELECT
, más o menos un 2.5% más rápido en consultas sin preparar y 6.7% en consultas preparadas.
Aún así puede que estas diferencias de rendimiento cambien en el futuro. Este es un punto muy importante a considerar si es que el rendimiento es importante para tí.
Y el ganador es…
Claramente PDO se lleva el galardón por la variedad de funciones que ofrece frente a su competidor. Si no los estas usando ya, deberías pasarte inmediatamente, a no ser que realmente te importe la pequeña pérdida de rendimiento.
¿Y vosotros cuál usáis? ¿Que opinais sobre el tema? No dudéis en espresar vuestras opiniones.