Uso de MySQL con PDO – PHP (II). Tratamiento de excepciones.

Facebooktwittergoogle_pluslinkedinmailFacebooktwittergoogle_pluslinkedinmail

En el artículo anterior aprendimos a crear una conexión PDO con una base de datos, además de hacer las operaciones más habituales. Si recuerdas lo que allí vimos, al establecer los atributos de la conexión le indicábamos a nuestro objeto PDO que “estuviera listo” para tratar con excepciones, así:

$conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Y ¿Qué son las excepciones? Bueno. Si estás familiarizado con la Programación Orientada a Objetos, no digo nada. Si no es el caso, excepciones son errores que pueden producirse en tiempo de ejecución, y que no necesariamente se deben a un error de sintaxis. Por ejemplo, tratar de leer una columna de una tabla que no existe (por haber equivocado el nombre), lanza una excepción.

En este artículo veremos como detectar, localizar y manejar las excepciones.

EL ESCENARIO

Ya que en el anterior artículo estuvimos trabajando con tablas de personas de distintas ciudades, vamos a preparar un escenario similar para este artículo. La base de datos se llama contactos y tiene tres tablas: paises, ciudades y personas. La hemos nutrido con algunos datos para pruebas, y la hemos estructurado de forma que la tabla paises tiene una relación específica con la tabla ciudades y esta, a su vez, con la tabla personas. Para ponértelo fácil, la base de datos completa te la puedes descargar en este enlace. A fin de que podamos seguir mejor el artículo, te reproduzco, a continuación, la estructura (sin datos, que por ahora, nos dan un poco igual).

UNA EXCEPCIÓN

Vamos a ver un caso típico de excepciones que pueden darse con PDO: Al programar una consulta, nos hemos equivocado con el nombre de una columna (o algún otro programador de nuestro equipo lo ha cambiado en la estructura, y no nos ha dicho nada, que esas cosas pasan). Suponte que tienes, en tu PHP, una consulta como la siguiente:

Parece correcta y, desde luego, sintácticamente, lo es. Pero observa la línea resaltada. Está haciendo referencia al campo de la tabla personas que almacena la fecha de nacimiento de cada persona que tenemos registrada. Pero, en la estructura de la tabla, esta columna se llama fecha_nacimiento, y en el código hemos escrito fecha_de_nacimiento. Catástrofe en ciernes por un tontería. Cuando intentas ejecutar tu PHP con esta consulta, la ejecución se aborta con una salida en pantalla que, al menos al principio, asusta un poco:

Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘personas.fecha_de_nacimiento’ in ‘field list’ in C:\xampp\htdocs\pdo\consulta_compleja.php:21 Stack trace: #0 C:\xampp\htdocs\pdo\consulta_compleja.php(21): PDO->query(‘SELECT personas…’) #1 {main} thrown in C:\xampp\htdocs\pdo\consulta_compleja.php on line 21

En realidad, este mensaje nos ayuda enormemente, proporcionádonos una gran cantidad de información sobre la causa del problema y, por tanto, la mejor forma de solucionarlo. En primer lugar, observa la frase Uncaught PDOException. Ya se nos está informando de que se ha producido una excepción, y y que no la hemos previsto de ningún modo (palabra Uncaught, que podríamos traducir por no prevista o, más exactamente, no capturada). Las excepciones que se pueden producir cuando se trabaja con el paradigma de Programación Orientada a Objetos están tipificadas en base al objeto o proceso que las lanza. En concreto, una excepción del tipo PDOException (cómo vemos en el mensaje) está producida por un objeto PDO.

También tenemos un código de error SQL, y su significado: Column not found: 1054. Cada excepción lanzada por SQL tiene un código que la identifica. El 1054 corresponde a una columna que no se ha encontrado en la tabla en la que se buscaba.

Además, el mensaje nos informa de cual es la columna que estábamos buscando y no se ha encontrado: Unknown column 'personas.fecha_de_nacimiento'.

También se nos informa del nombre del script que ha lanzado la excepción, y la línea concreta en la que se ha lanzado: C:\xampp\htdocs\pdo\consulta_compleja.php on line 21. Y aquí, la cosa puede ponerse un poco más complicada de localizar. En mi script, por ejemplo, la línea PHP donde se menciona la columna que no existe es la 9. Sin embargo, el mensaje me dice que la excepción se ha lanzado en la línea 21. Esta es la que trata de ejecutar la consulta, pero esa línea en concreto no tiene ningún error, así que nos vemos obligados a revisar la consulta en sí, no la línea indicada. El código usado para esta prueba es el siguiente:

CAPTURANDO LA EXCEPCIÓN

Llegados a este punto hay dos cosas que tenemos que hacer. En este caso, por supuesto, corregir el nombre del campo en el código PHP, para que la lectura pueda llevarse a cabo sin problemas. Pero también debemos prever que, en el futuro, pueda producirse otra excepción, quizá, incluso, cuando el código ya esté en producción, a disposición del público. No podemos permitir que el usuario vea un fallo así, por dos razones fundamentales: por una parte, queda horrible, y seguro que los usuarios no van a hablar bien de nuestra página. Por otro lado, un mensaje como este proporciona información sensible a un posible atacante.

Lo que se hace en estos casos es prever que, de producirse una excepción, el script nos de una “salida honrosa”. Para ello usamos un bloque de sentencias conocidas como try...catch. Esto significa que el script debe intentar (try) ejecutar el proceso que le pedimos pero, si se produce una excepción, debe capturarla (catch) para proporcionar una alternativa. Observa la nueva versión del script:

Observa las líneas resaltadas. En el bloque try hemos declarado las instrucciones que el script debe tratar de ejecutar, y que, de hecho, ejecutará si todo va bien. En el bloque catch capturamos la excepción si se produce. Declaramos el tipo de excepción que puede producirse en cada caso. Los objetos PDO lanzan excepciones del tipo PDOException, por lo que ese es el tipo que debemos prever.

DURANTE EL DESARROLLO

Cuando se trabaja con Programación Orientada a Objetos, la excepciones también son objetos y, cómo tales, podemos trabajar con ellos. Al declarar que estamos capturando una PDOException, y asignarla a una variable (en este caso, $e), podemos, dentro del bloque catch, obtener información adicional que nos ayude en la depuración. Imagina que el bloque try...catch lo escribimos así:

Observa que en la línea resaltada hacemos un volcado de la excepción. Esto se emplea mucho en desarrollo, durante la depuración aunque, por supuesto, nunca subiremos un código así a producción. El objeto PDOException tiene gran cantidad de propiedades que nos informan de cual ha sido el error, y la posible causa y solución. De hecho, este código proporciona la siguiente salida en pantalla:

Como ves, este objeto tiene gran catidad de propiedades útiles para la depuración. Por ejemplo, la propiedad args es una matriz cuyo primer y único elemento es la consulta que hemos tratado de realizar. La propiedad errorInfo es una matriz con tres elementos: El primero es el código de la excepción, el segundo, el código del error SQL y, por último, el tercero una descripción de dicho error SQL.

Además, hasta que te familiarices con esto, las excepciones tienen métodos que pueden ayudarte a facilitar la lectura de lo que ha pasado. Imagina que el bloque try...catch lo definimos así:

Estos métodos “despiezan” la información sobre la excepción, facilitándonos la lectura y consiguiente depuración. El resultado en pantalla sería similar a este:

Mensaje de la excepción: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘personas.fecha_de_nacimiento’ in ‘field list’
Excepción previa (para posibles seguimientos):
Código de la excepción: 42S22
Script causante de la excepción: C:\xampp\htdocs\pdo\consulta_compleja.php
Línea causante de la excepción: 22
Cadena informativa de la excepción: PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘personas.fecha_de_nacimiento’ in ‘field list’ in C:\xampp\htdocs\pdo\consulta_compleja.php:22 Stack trace: #0 C:\xampp\htdocs\pdo\consulta_compleja.php(22): PDO->query(‘SELECT personas…’) #1 {main}

Cómo ves, el manejo de excepciones en PDO es fundamental, tanto durante el desarrollo como en producción.

     

Un comentario:

  1. Pingback: Uniendo tablas MySQL (I). Introducción. – Recursos para programadores

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *