jairogarcíarincón

Utilización de bases de datos mediante PDO (PHP Data Objects)


5.66K

Introducción

Como comentamos al inicio del capítulo, existe la posibilidad de utilizar una capa de abstracción para el acceso a datos que permita, en un futuro, adaptar de forma sencilla nuestro código a cualquier otro servidor de almacenamiento.

Además, el uso de esta capa de abstracción simplifica considerablemente el proceso de conexión y establecimiento de consultas en la mayoría de los casos.

Existen varias opciones, aunque la más adecuada para PHP es PDO (PHP Data Objects), basado en las características de la programación orientada a objetos de PHP.

Lo primero que debemos comprobar es si tenemos el controlador para PDO específico que necesitamos, en nuestro caso, el de MySQL, y la forma más sencilla de comprobarlo es mediante un script con la instrucción phpinfo(); y buscar en ella el controlador pdo_mysql.

Conexión

Para poder conectarte a una base de datos con PDO desde un script PHP necesitamos instanciar un objeto de la clase PDO con los siguientes parámetros (en ese orden):

  • Origen de datos (DSN o Data Source Name): Un string que indica el controlador a utilizar, seguido de dos puntos, el nombre del servidor de base de datos y el nombre de la base de datos
  • El usuario de la base de datos
  • La contraseña de la base de datos


De este modo, suponiendo que hemos creado una base de datos y un usuario para la misma, puedo conectarme a la base de datos de tres maneras diferentes:


//Conexión mediante PDO
$db = new PDO('mysql:host=localhost;dbname=amazonaws', 'amazonaws', 'amazonaws');


De manera opcional, podríamos indicar el puerto el socket de la siguiente forma:


//Conexión mediante PDO
$db = new PDO('mysql:host=localhost;dbname=amazonaws;port=3306;unix_socket=/tmp/mysql.sock', 'amazonaws', 'amazonaws');


Por último, es posible además añadir un array de opciones de conexión, como por ejemplo para indicar el juego de caracteres UTF-8:


//Conexión mediante PDO
$opciones = [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"];
$db = new PDO('mysql:host=localhost;dbname=amazonaws', 'amazonaws', 'amazonaws', $opciones);


O con gestión de errores de conexión:


//Conexión con control de errores
$opciones = [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"];
try {
$db = new PDO('mysql:host=localhost;dbname=amazonaws', 'amazonaws', 'amazonaws', $opciones);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Falló la conexión: ' . $e->getMessage();
}



Una vez establecida la conexión, puedo comprobar la versión mediante el comando:


//Comprobación de la versión
echo $db->getAttribute(PDO::ATTR_SERVER_VERSION);


Consultas

Al igual que nos ocurría en el caso de mysqli, a la hora de realizar las consultas debemos diferenciar entre aquellas que devuelven conjuntos de datos (SELECT) de aquellas de acción que no los devuelven (INSERT, UPDATE y DELETE).

Así, en INSERT, DELETE y UPDATE el método exec() devuelve el número de registros afectados, mientras que en SELECT, devuelve un objeto de tipo PDOStatement que tendremos que recorrer.


//Insert
$registros = $db->exec('INSERT INTO personas (nombre) VALUES ("José"),("Luís")');
if ($registros){
echo "Se han activado $registros registros.";
}

//Delete
$registros = $db->exec('DELETE FROM personas WHERE id>3');
if ($registros){
echo "Se han activado $registros registros.";
}

//Update
$registros = $db->exec('UPDATE personas SET activo=1 WHERE activo=0');
if ($registros){
echo "Se han activado $registros registros.";
}
echo "
";

//Select con BOTH
$resultado = $db->query('SELECT * FROM personas');
while ($personas = $resultado->fetch()){ //O bien ($resultado->fetch(PDO::FETCH_BOTH)
echo $personas['id']." ".$personas[1]." ".$personas['activo']."<br>";
}

//Select con ASSOC
$resultado = $db->query('SELECT * FROM personas');
while ($personas = $resultado->fetch(PDO::FETCH_ASSOC)){ //Recorro el resultado
echo $personas['id']." ".$personas['nombre']." ".$personas['activo']."<br>";
}

//Select con NUM
$resultado = $db->query('SELECT * FROM personas');
while ($personas = $resultado->fetch(PDO::FETCH_NUM)){ //Recorro el resultado
echo $personas[0]." ".$personas[1]." ".$personas[2]."<br>";
}

//Select con OBJ
$resultado = $db->query('SELECT * FROM personas');
while ($personas = $resultado->fetch(PDO::FETCH_OBJ)){ //Recorro el resultado
echo $personas->id." ".$personas->nombre." ".$personas->activo."<br>";
}

//Select con LAZY
$resultado = $db->query('SELECT * FROM personas');
while ($personas = $resultado->fetch(PDO::FETCH_LAZY)){ //Recorro el resultado
echo $personas[0]." ".$personas['nombre']." ".$personas->activo."<br>";
}

//Select con BOUND
$resultado = $db->query('SELECT * FROM personas');
$resultado->bindColumn(1, $id);
$resultado->bindColumn(2, $nombre);
$resultado->bindColumn(3, $activo);
while ($personas = $resultado->fetch(PDO::FETCH_BOUND)){ //Recorro el resultado
echo $id." ".$nombre." ".$activo."<br>";
}


De la misma manera que ocurría con mysqli, fetch() devuelve por defecto un array con claves numéricas y asociativas, si es esto es modificable añadiendo las siguientes constantes predefinidas:

  • PDO::FETCH_ASSOC. Devuelve solo el array asociativo
  • PDO::FETCH_NUM. Devuelve solo el array numérico
  • PDO::FETCH_BOTH. Devuelve los dos. Es el comportamiento por defecto
  • PDO::FETCH_OBJ. Devuelve un objeto cuyas propiedades coinciden con las columnas de la tabla / campos del registro
  • PDO::FETCH_LAZY. Devuelve el objeto y el array con clave dual de FETCH_BOTH
  • PDO::FETCH_BOUND. Devuelve true y asigna los valores del registro a variables según se indique en el método bindColumn (ver ejemplo anterior)


Transacciones

En PDO ocurre como en mysqli, esto es, cada consulta es una transacción en si misma ya que el comportamiento por defecto es el de autocommit, si bien es posible modificarlo de la siguiente forma (siempre que el motor utilizado permita el uso de transacciones, como InnoDB):


//Iniciamos la trasnacción para que no ejecute cada una de ellas por separado
$db->beginTransaction();
//Declaramos todas las consultas
$resultado = $db->exec('INSERT INTO personas (nombre) VALUES ("José"),("Luís")');
$resultado = $db->exec('DELETE FROM personas WHERE id>3');
$resultado = $db->exec('UPDATE personas SET activo=1 WHERE activo=0');
//Realizamos el commit para que se ejecuten todas las consultas
$db->commit();
//Mensaje
if ($resultado){
echo "Se han activado $resultado registros.
";
}
echo "
";
//Y si no ha salido como esperábamos, podemos revertir las consultas mediante
$db->rollback();


Consultas preparadas

De nuevo y de forma similar a como hacíamos en mysqli, es posible utilizar consultas preparadas o statements:


//Consulta preparada
$nombres = ['Jorgito', 'Juanito', 'Jaimito'];
$resultado = $db->prepare('INSERT INTO personas (nombre) VALUES (?)');
//O bien $resultado = $db->prepare('INSERT INTO personas (nombre) VALUES (:nombre)');
foreach ($nombres as $nombre){
$resultado->bindParam(1, $nombre); //O bien $resultado->bindParam(':nombre', $nombre);
$resultado->execute();
}
$db = null;


Fuentes: Wikipedia, php.net y José Luís Comesaña.


Publicado el 24 de Abril de 2025

phpmysqlobjetos