Manejo de excepciones en PHP

La excepción (Exception) se utiliza para cambiar el flujo normal del script en situaciones de error especificadas.

¿Qué es una excepción?

PHP 5 ofrece un nuevo método de manejo de errores orientado a objetos.

El manejo de excepciones se utiliza para cambiar el flujo normal del script en situaciones de error (excepciones). Esta situación se llama excepción.

Cuando se desencadena una excepción, generalmente ocurre:

  • El estado actual del código se guarda
  • La ejecución del código se cambia al función de procesador de excepciones predefinida
  • Dependiendo de la situación, el procesador puede reiniciar la ejecución del código desde el estado guardado, detener la ejecución del script o continuar el script desde otra ubicación del código

Vamos a mostrar diferentes métodos de manejo de errores:

  • Uso básico de excepciones
  • Creación de un gestor de excepciones personalizado
  • Múltiples excepciones
  • Re lanzar la excepción
  • Configuración del gestor de excepciones superior

Uso básico de excepciones

Cuando se lanza una excepción, el código posterior no se ejecutará, PHP intentará buscar un bloque de código "catch" correspondiente.

Si la excepción no se captura y no se utiliza set_exception_handler() para manejarla adecuadamente, se producirá un error grave (error fatal) y se mostrará el mensaje de error "Excepción no capturada".

Vamos a intentar lanzar una excepción sin capturarla:

<?php
//crear función con una excepción
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("El valor debe ser 1 o menor");
  }
 return true;
 }
//desencadenar excepción
checkNum(2);
?>

El código anterior generará un error similar a este:

Error fatal: Excepción no atrapada 'Exception' 
con el mensaje 'El valor debe ser 1 o inferior' en C:\webfolder\test.php:6 
Rastro de pila: #0 C:\webfolder\test.php(12): 
checkNum(28) #1 {main} lanzado en C:\webfolder\test.php en la línea 6

Try, throw y catch

Para evitar los errores que se presentan en el ejemplo anterior, necesitamos crear el código adecuado para manejar las excepciones.

El manejo correcto debe incluir:

  1. Intentar - Las funciones que lanzan excepciones deben estar ubicadas dentro de un bloque de código "try". Si no se desencadena una excepción, el código se ejecutará como de costumbre. Sin embargo, si se desencadena una excepción, se lanzará una excepción.
  2. Throw - Aquí se especifica cómo se lanza una excepción. Cada "throw" debe tener al menos un "catch" correspondiente.
  3. Catch - El bloque de código "catch" captura la excepción y crea un objeto que contiene información sobre la excepción

Vamos a lanzar una excepción:

<?php
//Crear una función que puede lanzar una excepción
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("El valor debe ser 1 o menor");
  }
 return true;
 }
//Generar excepción en el bloque de código "try"
try
 {
 checkNum(2);
 //Si se lanza la excepción, este texto no se mostrará
 echo 'Si ves esto, el número es 1 o menor';
 }
//Capturar excepción
catch(Exception $e)
 {
 echo 'Mensaje: ' .$e->getMessage();
 }
?>

El código anterior generará un error similar a este:

Mensaje: El valor debe ser 1 o menor

Ejemplo de explicación:

El código anterior lanza una excepción y la captura:

  1. Crear la función checkNum(). Detecta si el número es mayor de 1. Si lo es, lanza una excepción.
  2. Llamar a la función checkNum() dentro del bloque de código "try".
  3. La excepción en la función checkNum() se lanza
  4. El bloque de código "catch" recibe la excepción y crea un objeto que contiene información sobre la excepción ($e).
  5. Al llamar a $e->getMessage() desde este objeto exception, se muestra el mensaje de error de la excepción.

Sin embargo, para seguir el principio de "cada throw debe tener un catch", se puede configurar un gestor de excepciones superior para manejar errores omitidos.

Crear una clase Exception personalizada

Crear un gestor de excepciones personalizado es muy simple. Simplemente creamos una clase especial que puede llamar a sus funciones cuando ocurre una excepción en PHP. Esta clase debe ser una extensión de la clase exception.

Esta clase exception personalizada hereda todas las propiedades de la clase exception de PHP, a la que puedes agregar funciones personalizadas.

Comenzamos a crear la clase exception:

<?php
class customException extends Exception
 {
 public function errorMessage()
  {
  //mensaje de error
  $errorMsg = 'Error en la línea '.$this->getLine().' en '.$this->getFile()
  : <b>'.$this->getMessage().'</b> no es una dirección de correo electrónico válida
  return $errorMsg;
  }
 }
$email = "someone@example...com";
try
 {
 //comprobar si 
 if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
  {
  //lanzar excepción si el correo electrónico no es válido
  throw new customException($email);
  }
 }
catch (customException $e)
 {
 //mostrar mensaje personalizado
 echo $e->errorMessage();
 }
?>

Esta nueva clase es una copia de la clase de excepción antigua, más la función errorMessage(). Debido a que es una copia de la clase antigua, hereda las propiedades y métodos de la clase antigua, podemos usar los métodos de la clase excepción, como getLine(), getFile() y getMessage().

Ejemplo de explicación:

El código anterior lanza una excepción y la captura a través de una clase de excepción personalizada:

  1. La clase customException se creó como una extensión de la clase exception antigua. De esta manera, hereda todas las propiedades y métodos de la clase antigua.
  2. Crear la función errorMessage(). Si la dirección de correo electrónico no es válida, esta función devuelve un mensaje de error
  3. Establecer la variable $email como una cadena de caracteres de correo electrónico no válido
  4. Ejecutar el bloque "try", debido a que la dirección de correo electrónico no es válida, se lanzará una excepción
  5. El bloque "catch" captura la excepción y muestra el mensaje de error

Múltiples excepciones

Se pueden usar varias excepciones para un fragmento de script para detectar varios casos.

Se pueden usar varios bloques if..else o un bloque switch, o anidar varias excepciones. Estas excepciones pueden usar diferentes clases de excepción y devolver diferentes mensajes de error:

<?php
class customException extends Exception
{
public function errorMessage()
{
//mensaje de error
$errorMsg = 'Error en la línea '.$this->getLine().' en '.$this->getFile()
: <b>'.$this->getMessage().'</b> no es una dirección de correo electrónico válida
return $errorMsg;
}
}
$email = "someone@example.com";
try
 {
 //comprobar si 
 if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
  {
  //lanzar excepción si el correo electrónico no es válido
  throw new customException($email);
  }
 //verificar si "example" está en la dirección de correo
 if(strpos($email, "example") !== FALSE)
  {
  throw new Exception("$email es un e-mail de ejemplo");
  }
 }
catch (customException $e)
 {
 echo $e->errorMessage();
 }
catch(Exception $e)
 {
 echo $e->getMessage();
 }
?>

Ejemplo de explicación:

El código anterior prueba dos condiciones, y si ninguna de las condiciones se cumple, se lanzará una excepción:

  1. La clase customException se creó como una extensión de la clase exception antigua. De esta manera, hereda todas las propiedades y métodos de la clase antigua.
  2. Se creó la función errorMessage(). Si la dirección de correo electrónico no es válida, esta función devuelve un mensaje de error.
  3. Ejecutar el bloque "try", no se lanzará una excepción bajo la condición primera.
  4. Dado que el e-mail contiene la cadena "example", la segunda condición desencadenará la excepción.
  5. El bloque "catch" captura la excepción y muestra el mensaje de error apropiado

Si no se captura customException y solo se captura base exception, maneje la excepción allí.

Re lanzar la excepción

A veces, cuando se lanza una excepción, es posible que desee manejarla de una manera diferente a la estándar. Puede lanzar la excepción nuevamente en un bloque "catch".

El script debe ocultar los errores del sistema al usuario. Los errores del sistema pueden ser importantes para los programadores, pero los usuarios no están interesados en ellos. Para que sea más fácil de usar para el usuario, puede lanzar una excepción con un mensaje más amigable para el usuario:

<?php
class customException extends Exception
 {
 public function errorMessage()
  {
  //mensaje de error
  $errorMsg = $this->getMessage().' no es una dirección de correo electrónico válida.';
  return $errorMsg;
  }
 }
$email = "someone@example.com";
try
 {
 try
  {
  //verificar si "example" está en la dirección de correo
  if(strpos($email, "example") !== FALSE)
   {
   //lanzar excepción si el correo electrónico no es válido
   throw new Exception($email);
   }
  }
 catch(Exception $e)
  {
  //volver a lanzar excepción
  throw new customException($email);
  }
 }
catch (customException $e)
 {
 //mostrar mensaje personalizado
 echo $e->errorMessage();
 }
?>

Ejemplo de explicación:

El código anterior detecta si la dirección de correo electrónico contiene la cadena "example". Si es así, lanza la excepción nuevamente:

  1. La clase customException se creó como una extensión de la clase exception antigua. De esta manera, hereda todas las propiedades y métodos de la clase antigua.
  2. Se creó la función errorMessage(). Si la dirección de correo electrónico no es válida, esta función devuelve un mensaje de error.
  3. Se estableció la variable $email como una dirección de correo válida, pero contiene la cadena "example".
  4. El bloque de código "try" contiene otro bloque "try", lo que permite lanzar la excepción nuevamente.
  5. Se desencadenó la excepción porque el e-mail contiene la cadena "example".
  6. "catch" capturó la excepción y volvió a lanzar "customException".
  7. Se capturó "customException" y se mostró un mensaje de error.

Si la excepción no se captura en el bloque try actual, buscará un bloque catch en niveles superiores.

Configuración del gestor de excepciones de nivel superior (Top Level Exception Handler)

La función set_exception_handler() puede configurar un usuario definido para manejar todas las excepciones no capturadas.

<?php
function myException($exception)
{
echo "<b>Exception:</b> " , $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Exception no capturada ocurrió');
?>

La salida del código anterior debería ser similar a esto:

Exception: Exception no capturada ocurrió

En el código anterior, no existe un bloque "catch", sino que se activa el programa de manejo de excepciones de nivel superior. Debe usar esta función para capturar todas las excepciones no capturadas.

Reglas de excepciones

  • El código que requiere manejo de excepciones debe colocarse dentro de un bloque try, para capturar posibles excepciones.
  • Cada bloque try o throw debe tener al menos un bloque catch correspondiente.
  • Con múltiples bloques catch se pueden capturar diferentes tipos de excepciones.
  • Se puede lanzar una excepción nuevamente en el bloque catch del código try.

En resumen: si se lanza una excepción, debe capturarlo.