handling exceptions example error custom catch all php exception

exceptions - php throw



Mensajes de excepción personalizados: mejores prácticas (5)

Consulte Cómo diseñar jerarquías de excepciones en el blog de Krzysztof Cwalina, coautor de "Pautas de diseño de marcos".

¿Me pregunto cuánto esfuerzo debo hacer para forzar información de depuración útil al crear mensajes de excepción, o debería simplemente confiar en que el usuario proporcione la información correcta, o difiera la recopilación de información a un manejador de excepciones?

Veo mucha gente haciendo excepciones, como:

throw new RuntimeException(''MyObject is not an array'')

o extendiendo las excepciones predeterminadas con excepciones personalizadas que no hacen mucho pero cambian el nombre de la excepción:

throw new WrongTypeException(''MyObject is not an array'')

Pero esto no proporciona mucha información de depuración ... y no impone ningún tipo de formato con el mensaje de error. Por lo tanto, podría terminar exactamente con el mismo error produciendo dos mensajes de error diferentes ... por ejemplo, "Falló la conexión de la base de datos" frente a "No se pudo conectar a la base de datos".

Claro, si sube a la cima, imprimirá el trazado de la pila, lo cual es útil, pero no siempre me dice todo lo que necesito saber y, por lo general, termino teniendo que empezar a disparar las declaraciones var_dump () para descubrir qué salió mal y dónde ... aunque esto podría compensarse con un manejador de excepción decente.

Estoy empezando a pensar en algo como el siguiente código, donde requiero que el lanzador de la excepción proporcione argumentos necesarios para producir el mensaje de error correcto. Estoy pensando que este podría ser el camino a seguir en eso:

  • Se debe suministrar un nivel mínimo de información útil
  • Produce mensajes de error algo consistentes
  • Plantillas para mensajes de excepción, todo en la única ubicación (clases de excepción), por lo que es más fácil actualizar los mensajes ...

Pero veo que la desventaja es que son más difíciles de usar (requiere que busque la definición de excepción), y por lo tanto puede desalentar a otros programadores de usar excepciones provistas ...

Me gustaría un comentario sobre esta idea y las mejores prácticas para un marco de mensajes de excepción consistente y flexible.

/** * @package MyExceptions * MyWrongTypeException occurs when an object or * datastructure is of the incorrect datatype. * Program defensively! * @param $objectName string name of object, eg "/$myObject" * @param $object object object of the wrong type * @param $expect string expected type of object eg ''integer'' * @param $message any additional human readable info. * @param $code error code. * @return Informative exception error message. * @author secoif */ class MyWrongTypeException extends RuntimeException { public function __construct($objectName, $object, $expected, $message = '''', $code = 0) { $receivedType = gettype($object) $message = "Wrong Type: $objectName. Expected $expected, received $receivedType"; debug_dump($message, $object); return parent::__construct($message, $code); } }

....

/** * If we are in debug mode, append the var_dump of $object to $message */ function debug_dump(&$message, &$object) { if (App::get_mode() == ''debug'') { ob_start(); var_dump($object); $message = $message . "Debug Info: " . ob_get_clean(); } }

Luego se usa como:

// Hypothetical, supposed to return an array of user objects $users = get_users(); // but instead returns the string ''bad'' // Ideally the $users model object would provide a validate() but for the sake // of the example if (is_array($users)) { throw new MyWrongTypeException(''$users'', $users, ''array'') // returns //"Wrong Type: $users. Expected array, received string }

y podríamos hacer algo como un nl2br en un manejador de excepciones personalizado para hacer cosas agradables para la salida html.

Estado leyendo: http://msdn.microsoft.com/en-us/library/cc511859.aspx#

Y no hay mención de algo así, así que tal vez es una mala idea ...


No voy a desmerecer el asesoramiento sobre el blog de Krzysztof, pero aquí hay una manera fácil de crear excepciones personalizadas.

Ejemplo:

<?php require_once "CustomException.php"; class SqlProxyException extends CustomException {} throw new SqlProxyException($errorMsg, mysql_errno()); ?>

El código detrás de eso (que pedí prestado en alguna parte, disculpas a quien sea que fue)

<?php interface IException { /* Protected methods inherited from Exception class */ public function getMessage(); // Exception message public function getCode(); // User-defined Exception code public function getFile(); // Source filename public function getLine(); // Source line public function getTrace(); // An array of the backtrace() public function getTraceAsString(); // Formated string of trace /* Overrideable methods inherited from Exception class */ public function __toString(); // formated string for display public function __construct($message = null, $code = 0); } abstract class CustomException extends Exception implements IException { protected $message = ''Unknown exception''; // Exception message private $string; // Unknown protected $code = 0; // User-defined exception code protected $file; // Source filename of exception protected $line; // Source line of exception private $trace; // Unknown public function __construct($message = null, $code = 0) { if (!$message) { throw new $this(''Unknown ''. get_class($this)); } parent::__construct($message, $code); } public function __toString() { return get_class($this) . " ''{$this->message}'' in {$this->file}({$this->line})/n" . "{$this->getTraceAsString()}"; } }


Nunca, nunca confíe en que un usuario ''haga lo correcto'' e incluya información para la depuración. Si desea información, debe reunirla usted mismo y almacenarla en algún lugar accesible.

También como se dijo, si es difícil (er) hacer algo, los usuarios evitarán hacerlo, por lo que, nuevamente, no dependan de su buena voluntad y de su conocimiento de lo que deben enviar.

Este pensamiento implica un método mediante el cual se recopila la información y se registra, lo que implica el uso de var_dump () en algún lugar.

Además, como dice Mark Harrison, un botón que facilita el envío de un mensaje de error a alguna parte es fantástico para usted y para los usuarios. Les facilita reportar un error. Usted (como destinatario) obtiene muchos duplicados, pero la información duplicada es mejor que no tener información.


Recomiendo encarecidamente el consejo en el blog de Krzysztof y notaría que, en su caso, parece que está tratando de lidiar con lo que él llama Errores de uso.

En este caso, lo que se requiere no es un nuevo tipo para indicarlo, sino un mejor mensaje de error sobre qué lo causó. Como tal, una función de ayuda a:

  1. generar la cadena de texto para colocar en la excepción
  2. generar la excepción y el mensaje completos

Es lo que se requiere

El Método 1 es más claro, pero puede llevar a un uso un poco más detallado, 2 es lo opuesto, cambiando una sintaxis de Terser por menos claridad.

Tenga en cuenta que las funciones deben ser extremadamente seguras (nunca deben, nunca, causar una excepción no relacionada) y no forzar la provisión de datos que es opcional en ciertos usos razonables.

Al usar cualquiera de estos enfoques, es más fácil internacionalizar el mensaje de error más adelante si es necesario.

Una traza de pila como mínimo le da la función, y posiblemente el número de línea, por lo que debe centrarse en el suministro de información que no es fácil de resolver a partir de eso.


Sin importar los detalles que agregue, asegúrese de que

  • facilite cortar y pegar todo, o
  • tener un botón que informará el error para ellos