Cyber Monday Sale 40% off unlimited courses & creative assets! 40% off unlimited assets! Save Now
Advertisement
  1. Code
  2. PHP

Por qué deberías usar PDO de PHP para acceder a las bases de datos

by
Read Time:14 minsLanguages:

Spanish (Español) translation by Ana Paulina Figueroa Vazquez (you can also view the original English article)

Muchos programadores de PHP aprendieron cómo acceder a las bases de datos usando ya sea la extensión MySQL o la extensión MySQLi. A partir de PHP 5.1 hay una forma mejor. La extensión Objetos de Datos de PHP (PDO, o PHP Data Objects en inglés) proporciona métodos para sentencias preparadas y para trabajar con objetos ¡que permitirán que seas mucho más productivo!

Tutorial publicado nuevamente

Cada cierto tiempo volvemos a revisar algunas de las publicaciones favoritas de nuestros lectores a lo largo de la historia del sitio. Este tutorial fue publicado por primera vez en mayo de 2010.


Introducción a PDO

"PDO, u Objetos de Datos de PHP, es una capa de acceso a bases de datos que proporciona un método uniforme de acceso a múltiples bases de datos."

No toma en consideración la sintaxis específica de las bases de datos, pero puede permitir que el proceso de cambiar de bases de datos y plataformas sea bastante sencillo, simplemente cambiando la cadena de conexión en muchos casos.

PDO - db abstraction layer

Este tutorial no pretende ser un manual completo sobre SQL. Está escrito principalmente para personas que actualmente usan la extensión MySQL o MySQLi para ayudarles a dar el salto a PDO, una opción más portátil y potente.

Compatibilidad con bases de datos

La extensión es compatible con cualquier base de datos para la que se haya escrito un controlador PDO. En el momento de escribir este artículo están disponibles los siguientes controladores de bases de datos:

  • PDO_DBLIB (FreeTDS/Microsoft SQL Server/Sybase)
  • PDO_FIREBIRD (Firebird/Interbase 6)
  • PDO_IBM (DB2 de IBM)
  • PDO_INFORMIX (Servidor dinámico Informix de IBM)
  • PDO_MYSQL (MySQL 3.x/4.x/5.x)
  • PDO_OCI (Oracle Call Interface)
  • PDO_ODBC (ODBC v3 (DB2 de IBM, unixODBC y ODBC para win32))
  • PDO_PGSQL (PostgreSQL)
  • PDO_SQLITE (SQLite 3 y SQLite 2)
  • PDO_4D (4D)

No todos estos controladores están necesariamente disponibles en tu sistema; aquí puedes ver una forma rápida de averiguar qué controladores tienes:


Creando una conexión

Las diferentes bases de datos pueden tener métodos de conexión ligeramente distintos. A continuación se muestran los métodos para crear una conexión a algunas de las bases de datos más populares. Notarás que los primeros tres son idénticos, a excepción del tipo de base de datos, y luego SQLite tiene su propia sintaxis.

Connection String

Por favor toma nota del bloque try/catch (siempre debes envolver tus operaciones con PDO en un try/catch y usar el mecanismo para las excepciones). Más sobre esto en breve. Por lo general harás una sola conexión, y hay varias en la lista para mostrarte la sintaxis. $DBH significa "manejador de la base de datos" y será usado a lo largo de este tutorial.

Puedes cerrar cualquier conexión estableciendo null (nulo) como el valor del manejador.

Puedes obtener más información sobre opciones específicas de cada base de datos y/o cadenas de conexión para otras bases de datos en PHP.net.


Excepciones y PDO

PDO puede usar excepciones para gestionar errores, lo que significa que cualquier cosa que hagas con PDO debería incluirse en un bloque try/catch. Puedes forzar a PDO a trabajar en uno de tres modos de error configurando el atributo de modo de error en tu manejador de base de datos recién creado. Esta es la sintaxis:

Independientemente del modo de error que establezcas, un error de conexión siempre producirá una excepción, y la creación de una conexión siempre debería estar contenida en un bloque try/catch.

PDO::ERRMODE_SILENT

Este es el modo de error predeterminado. Si dejas este modo, tendrás que buscar errores de la manera en la que probablemente estás acostumbrado si usas las extensiones MySQL o MySQLi. Los otros dos métodos son más ideales para la programación en seco.

PDO::ERRMODE_WARNING

Este modo emitirá una advertencia estándar de PHP y permitirá que el programa siga ejecutándose. Es útil para depurar.

PDO::ERRMODE_EXCEPTION

Este es el modo que deberías querer usar en la mayoría de las situaciones. Este dispara una excepción, permitiéndote gestionar errores con elegancia y ocultar datos que pudieran ayudar a alguien a explotar tu sistema. Este es un ejemplo de cómo aprovechar las excepciones:

Hay un error intencional en la instrucción select; esto provocará una excepción. La excepción envía los detalles del error a un archivo de registro y muestra un mensaje amigable (o no tan amigable) al usuario.


La inserción y la actualización

La inserción de datos nuevos, o la actualización de datos existentes, es una de las operaciones más comunes en las bases de datos. Mediante el uso de PDO, normalmente este es un proceso de dos pasos. Todo lo cubierto en esta sección se aplica igualmente tanto a las operaciones UPDATE (actualizar) como a las operaciones INSERT (insertar).

2 to 3 step insert and update

Aquí puedes ver un ejemplo del tipo más básico de inserción:

También podrías llevar a cabo la misma operación usando el método exec() con una llamada menos. En la mayoría de las situaciones es conveniente usar el método más largo, con el fin de aprovechar las sentencias preparadas. Incluso si solamente lo vas a usar una vez, el uso de sentencias preparadas te ayudará a protegerte de los ataques de inyección SQL.

Sentencias preparadas

El uso de sentencias preparadas te ayudará a protegerte de la inyección SQL.

Una sentencia preparada es una sentencia SQL precompilada que puede ejecutarse múltiples veces enviando únicamente los datos al servidor. Tiene la ventaja adicional de hacer que los datos utilizados en los marcadores de posición estén a salvo de ataques de inyección SQL automáticamente.

Puedes usar una sentencia preparada incluyendo marcadores de posición en tu SQL. Aquí puedes ver tres ejemplos: uno sin marcadores de posición, uno con marcadores de posición sin nombres y uno con marcadores de posición con nombres.

Es recomendable que evites el primer método; aquí puedes verlo para compararlo. La elección de utilizar marcadores de posición con nombres o sin nombres afectará la manera en la que debes establecer los datos de esas sentencias.

Marcadores de posición sin nombres

Aquí hay dos pasos. Primero asignamos variables a los distintos marcadores de posición (líneas 2 a la 4). Después asignamos valores a esos marcadores de posición y ejecutamos la sentencia. Para enviar otro conjunto de datos, simplemente cambia los valores de esas variables y ejecuta la sentencia de nuevo.

¿Te parece un poco complicado en el caso de sentencias con muchos parámetros? Lo es. Sin embargo, si tus datos están almacenados en un arreglo, existe un atajo sencillo:

¡Eso es fácil!

Los datos del arreglo se aplican a los marcadores de posición en orden. $data[0] corresponde al primer marcador de posición, $data[1] al segundo y así sucesivamente. Sin embargo, si los índices de tu arreglo no están en orden, esto no funcionará correctamente y necesitarás indexar el arreglo de nuevo.

Marcadores de posición con nombres

Probablemente puedes adivinar la sintaxis, pero aquí tienes un ejemplo:

Aquí también puedes usar un atajo, pero funciona con arreglos asociativos. Este es un ejemplo:

Las claves de tu arreglo no necesitan comenzar con dos puntos, pero deben de coincidir con los marcadores de posición con nombres. Si tienes un arreglo de arreglos puedes iterar sobre ellos y simplemente llamar a la ejecución con cada arreglo de datos.

Otra característica interesante de los marcadores de posición con nombres es la posibilidad de insertar objetos directamente en tu base de datos, asumiendo que las propiedades coinciden con los campos con nombres. Aquí puedes ver un objeto de ejemplo y cómo puedes llevar a cabo tu inserción:

Al convertir el objeto a un arreglo en la instrucción execute, la propiedades son tratadas como claves de un arreglo.


Seleccionando datos

Fetch data into arrays or objects

Los datos se obtienen a través de ->fetch(), un método del manejador de tu sentencia. Antes de llamar a la función fetch, lo mejor es indicarle a PDO cómo te gustaría que se obtuvieran los datos. Tienes las siguientes opciones:

  • PDO::FETCH_ASSOC: devuelve un arreglo indexado por nombre de columna.
  • PDO::FETCH_BOTH (predeterminada): devuelve un arreglo indexado por nombre y por número de columna.
  • PDO::FETCH_BOUND: asigna los valores de tus columnas a las variables establecidas con el método ->bindColumn().
  • PDO::FETCH_CLASS: asigna los valores de tus columnas a propiedades de la clase con nombre. Esta opción creará las propiedades si no existen propiedades que coincidan.
  • PDO::FETCH_INTO: actualiza una instancia existente de la clase nombrada.
  • PDO::FETCH_LAZY: combina PDO::FETCH_BOTH/PDO::FETCH_OBJ, creando los nombres de la variable de tipo objeto a medida que se usan.
  • PDO::FETCH_NUM: devuelve un arreglo indexado por número de columna.
  • PDO::FETCH_OBJ: devuelve un objeto anónimo con nombres de propiedades que corresponden a los nombres de las columnas.

En realidad hay tres que cubrirán la mayoría de las situaciones: FETCH_ASSOC, FETCH_CLASS y FETCH_OBJ. Para configurar el método fetch se usa la siguiente sintaxis:

También puedes establecer el tipo de recuperación directamente dentro de la llamada al método ->fetch().

FETCH_ASSOC

Este tipo de recuperación crea un arreglo asociativo indexado por nombre de columna. Esto debería resultar bastante familiar para cualquiera que haya usado las extensiones MySQL/MySQLi. Este es un ejemplo de la selección de datos con este método:

El bucle while continuará recorriendo el conjunto de resultados una fila a la vez hasta que se termine.

FETCH_OBJ

Este tipo de recuperación crea un objeto de clase std para cada fila de datos recuperados. Este es un ejemplo:

FETCH_CLASS

Las propiedades de tu objeto se establecen ANTES de llamar al constructor. Esto es importante.

Este método de recuperación te permite recuperar datos directamente en una clase de tu elección. Cuando usas FETCH_CLASS, las propiedades de tu objeto se establecen ANTES de llamar al constructor. Lee eso nuevamente, es importante. Si las propiedades correspondientes a los nombres de las columnas no existen, esas propiedades serán creadas (como públicas) por ti.

Esto significa que, si tus datos necesitan alguna transformación después de que salen de la base de datos, tu objeto puede hacer eso automáticamente a medida que cada uno de ellos es creado.

Como ejemplo, imagina una situación en la que la dirección debe estar parcialmente oculta en cada registro. Podríamos hacer esto trabajando en esa propiedad en el constructor. Aquí puedes ver un ejemplo:

A medida que los datos se recuperan y almacenan en esta clase, todas las letras minúsculas de la dirección, de la a a la z, son reemplazadas por la letra x. Ahora bien, el uso de la clase y lograr que ocurra esa transformación de los datos es un proceso completamente transparente:

Si la dirección era "5 Rosebud", verías "5 Rxxxxxx" como tu salida. Por supuesto, puede haber situaciones en las que desees que se llame al constructor antes de que se asignen los datos. PDO también te tiene cubierto para hacer esto.

Ahora bien, cuando repites el ejemplo anterior con este modo de recuperación (PDO::FETCH_PROPS_LATE), la dirección NO se ocultará, ya que se llamó al constructor y luego se asignaron las propiedades.

Para finalizar, si realmente lo necesitas, puedes enviar argumentos al constructor al recuperar datos que se almacenan en objetos con PDO:

Si necesitas enviar datos diferentes al constructor de cada objeto, puedes establecer el modo de recuperación en el interior del método fetch:


Otros métodos útiles

Si bien este artículo no tiene como objetivo cubrir todo sobre PDO (¡es una extensión enorme!), hay algunos métodos más que es conveniente que conozcas para hacer cosas básicas con PDO.

El método ->lastInsertId() siempre se llama en el manejador de la base de datos, no en el manejador de la sentencia, y devolverá el id incrementado automáticamente de la última fila insertada por esa conexión.

El método ->exec() se usa para operaciones que no pueden devolver datos a excepción de las filas afectadas. Los anteriores son dos ejemplos del uso del método exec.

El método ->quote() coloca comillas en las cadenas para que sea seguro usarlas en las consultas. Esta es tu alternativa si no estás utilizando sentencias preparadas.

El método ->rowCount() devuelve un entero que indica la cantidad de filas afectadas por una operación. En al menos una versión conocida de PDO, de acuerdo a este reporte de error (http://bugs.php.net/40822), el método no funciona con instrucciones select. Si estás teniendo este problema y no puedes actualizar PHP, podrías obtener la cantidad de filas con lo siguiente:


Conclusión

Espero que esto ayude a algunos de ustedes a migrar de las extensiones MySQL y MySQLi. ¿Qué opinan? ¿Hay alguien entre ustedes que podría hacer el cambio?

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.