No debe atrapar la excepción a menos que tenga la intención de hacer algo significativo .
"Algo significativo" podría ser uno de estos:
Manejando la excepción
La acción significativa más obvia es manejar la excepción, por ejemplo, mostrando un mensaje de error y abortando la operación:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
Registro o limpieza parcial
A veces no sabes cómo manejar adecuadamente una excepción dentro de un contexto específico; quizás le falta información sobre el "panorama general", pero desea registrar la falla lo más cerca posible del punto en el que ocurrió. En este caso, es posible que desee atrapar, iniciar sesión y volver a lanzar:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
Un escenario relacionado es donde se encuentra en el lugar correcto para realizar una limpieza de la operación fallida, pero no para decidir cómo se debe manejar la falla en el nivel superior. En versiones anteriores de PHP esto se implementaría como
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
catch (Exception $e) {
$connect->disconnect(); // we don't want to keep the connection open anymore
throw $e; // but we also don't know how to respond to the failure
}
PHP 5.5 ha introducido la finally
palabra clave, por lo que para los escenarios de limpieza ahora hay otra forma de abordar esto. Si el código de limpieza necesita ejecutarse sin importar lo que sucedió (es decir, tanto por error como por éxito), ahora es posible hacerlo mientras se permite la propagación transparente de las excepciones lanzadas:
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
Abstracción de error (con encadenamiento de excepción)
Un tercer caso es donde desea agrupar lógicamente muchas posibles fallas bajo un paraguas más grande. Un ejemplo para la agrupación lógica:
class ComponentInitException extends Exception {
// public constructors etc as in Exception
}
class Component {
public function __construct() {
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);
}
}
}
En este caso, no desea que los usuarios Component
sepan que se implementa utilizando una conexión de base de datos (tal vez desee mantener abiertas sus opciones y utilizar el almacenamiento basado en archivos en el futuro). Por lo tanto, su especificación para Component
diría que "en el caso de un error de inicialización, ComponentInitException
será arrojado". Esto permite a los consumidores Component
detectar excepciones del tipo esperado, al tiempo que permite que el código de depuración acceda a todos los detalles (dependientes de la implementación) .
Proporcionando un contexto más rico (con excepción de encadenamiento)
Finalmente, hay casos en los que es posible que desee proporcionar más contexto para la excepción. En este caso, tiene sentido incluir la excepción en otra que contenga más información sobre lo que estaba tratando de hacer cuando ocurrió el error. Por ejemplo:
class FileOperation {
public static function copyFiles() {
try {
$copier = new FileCopier(); // the constructor may throw
// this may throw if the files do no not exist
$copier->ensureSourceFilesExist();
// this may throw if the directory cannot be created
$copier->createTargetDirectory();
// this may throw if copying a file fails
$copier->performCopy();
}
catch (Exception $e) {
throw new Exception("Could not perform copy operation.", 0, $e);
}
}
}
Este caso es similar al anterior (y el ejemplo probablemente no sea el mejor), pero ilustra el punto de proporcionar más contexto: si se produce una excepción, nos dice que la copia del archivo falló. ¿ Pero por qué falló? Esta información se proporciona en las excepciones envueltas (de las cuales podría haber más de un nivel si el ejemplo fuera mucho más complicado).
El valor de hacerlo se ilustra si piensa en un escenario en el que, por ejemplo, la creación de un UserProfile
objeto hace que los archivos se copien porque el perfil de usuario se almacena en archivos y admite la semántica de transacciones: puede "deshacer" los cambios porque solo se realizan en un copia del perfil hasta que te comprometas.
En este caso, si lo hiciste
try {
$profile = UserProfile::getInstance();
}
y como resultado se detectó un error de excepción "No se pudo crear el directorio de destino", tendría derecho a ser confundido. Ajustar esta excepción "principal" en capas de otras excepciones que proporcionan contexto hará que el error sea mucho más fácil de manejar ("Error al crear copia de perfil" -> "Error en operación de copia de archivo" -> "No se pudo crear el directorio de destino").