PDO vs MySQLi, ¿cuál debería estar usando?

A la hora de acceder a una base de datos en PHP tenemos dos opciones, PDO por un lado y MySQLi. ¿Cuál es la opción más recomendable? Analizemos todas las diferencias entre las dos.

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ísticaPDOMySQLi
Versión PHP donde se introdujo.5.15.0
Incluida con PHP 5.xSí.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.

comments powered by Disqus