MySQLi en PHP: la alternativa a PDO con consultas preparadas y modo orientado a objetos

MySQLi (MySQL Improved) es la extensión nativa de PHP para conectar con MySQL y MariaDB. A diferencia de PDO, que es una capa de abstracción multi-base-de-datos, MySQLi está optimizada específicamente para MySQL y ofrece algunas características exclusivas como la ejecución de múltiples queries y el acceso a ciertos metadatos de MySQL que PDO no expone. Ofrece dos APIs: procedural (mysqli_connect()) y orientada a objetos (new mysqli()). Esta guía usa la OOP.

Conectar con new mysqli()

<?php
$mysqli = new mysqli('localhost', 'usuario', 'contraseña', 'mi_base_datos');

if ($mysqli->connect_error) {
    throw new RuntimeException(
        "Error de conexión ({$mysqli->connect_errno}): {$mysqli->connect_error}"
    );
}

$mysqli->set_charset('utf8mb4');

Consultas preparadas con bind_param()

Las consultas preparadas son la forma correcta de trabajar con datos del usuario: evitan la inyección SQL separando el código de los datos.

<?php
// INSERT con consulta preparada
$stmt = $mysqli->prepare(
    "INSERT INTO usuarios (nombre, email, edad) VALUES (?, ?, ?)"
);

// 's' = string, 'i' = int, 'd' = double/float, 'b' = blob
$nombre = 'Ana García';
$email  = '[email protected]';
$edad   = 28;

$stmt->bind_param('ssi', $nombre, $email, $edad);
$stmt->execute();

echo "ID insertado: " . $mysqli->insert_id . "n"; // ID del registro nuevo
$stmt->close();

// SELECT con consulta preparada
$stmt = $mysqli->prepare("SELECT id, nombre, email FROM usuarios WHERE edad > ?");
$stmt->bind_param('i', $minEdad);
$minEdad = 25;
$stmt->execute();

get_result() vs bind_result()

Hay dos formas de recoger los resultados de un SELECT preparado:

<?php
// Opción 1: get_result() — más cómoda, requiere mysqlnd
$stmt = $mysqli->prepare("SELECT id, nombre, email FROM usuarios WHERE activo = ?");
$stmt->bind_param('i', $activo);
$activo = 1;
$stmt->execute();

$result = $stmt->get_result();
while ($fila = $result->fetch_assoc()) {
    echo "{$fila['nombre']} ({$fila['email']})n";
}

// Opción 2: bind_result() — compatible con todas las instalaciones
$stmt = $mysqli->prepare("SELECT id, nombre, email FROM usuarios WHERE activo = ?");
$stmt->bind_param('i', $activo);
$activo = 1;
$stmt->execute();

$stmt->bind_result($id, $nombre, $email);
while ($stmt->fetch()) {
    echo "$nombre ($email)n";
}
$stmt->close();

Transacciones

<?php
$mysqli->begin_transaction();

try {
    $stmtDescuento = $mysqli->prepare(
        "UPDATE cuentas SET saldo = saldo - ? WHERE id = ?"
    );
    $stmtDeposito  = $mysqli->prepare(
        "UPDATE cuentas SET saldo = saldo + ? WHERE id = ?"
    );

    $importe  = 500.00;
    $cuentaOrigen  = 1;
    $cuentaDestino = 2;

    $stmtDescuento->bind_param('di', $importe, $cuentaOrigen);
    $stmtDescuento->execute();

    $stmtDeposito->bind_param('di', $importe, $cuentaDestino);
    $stmtDeposito->execute();

    $mysqli->commit();
    echo "Transferencia completadan";
} catch (Exception $e) {
    $mysqli->rollback();
    echo "Error: " . $e->getMessage() . "n";
} finally {
    $stmtDescuento->close();
    $stmtDeposito->close();
}

Gestión de errores

<?php
// Activar excepciones (recomendado)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

// A partir de aquí, cualquier error lanzará una mysqli_sql_exception
try {
    $mysqli = new mysqli('localhost', 'usuario', 'pass', 'bd');
    $stmt   = $mysqli->prepare("SELECT * FROM tabla_inexistente");
    $stmt->execute();
} catch (mysqli_sql_exception $e) {
    echo "Error MySQL [{$e->getCode()}]: {$e->getMessage()}n";
}

MySQLi vs PDO: ¿cuándo elegir cada uno?

  • Usa MySQLi si tu proyecto usa exclusivamente MySQL/MariaDB, necesitas múltiples queries en una llamada (multi_query()), o quieres el rendimiento más ajustado con esa base de datos.
  • Usa PDO si tu proyecto puede cambiar de base de datos (SQLite para tests, PostgreSQL en producción), quieres una API más uniforme o prefieres fetchAll() con objetos tipados y named placeholders (:nombre en lugar de ?).

Ambas son opciones válidas y modernas. Lo que nunca debes usar son las funciones mysql_* (eliminadas en PHP 7) ni inyectar variables directamente en las queries.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP