Pregunta

¿Se pregunta cuánto esfuerzo debería hacer para forzar información útil de depuración al crear mensajes de excepción, o debería confiar en que el usuario proporcionará la información correcta o aplazar la recopilación de información a un controlador de excepciones?

Veo a muchas personas haciendo sus excepciones como:

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

o extender 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 con exactamente el mismo error produciendo dos mensajes de error diferentes ... por ejemplo, "La conexión de la base de datos falló". vs " No se pudo conectar a db "

Claro, si aparece en la parte superior, imprimirá el rastro de la pila, lo cual es útil, pero no siempre me dice todo lo que necesito saber y, por lo general, tengo que comenzar a disparar var_dump () declaraciones para descubrir qué salió mal y dónde ... aunque esto podría compensarse con un controlador de excepción decente.

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

  • Se debe proporcionar el nivel mínimo de información útil
  • Produce mensajes de error algo consistentes
  • Plantillas para mensajes de excepción en una sola 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 una definición de excepción) y, por lo tanto, podría disuadir a otros programadores de usar las excepciones proporcionadas ...

Me gustaría comentar sobre esta idea, & amp; 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 controlador de excepciones personalizado para hacer las cosas buenas para la salida html.

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

Y no se menciona nada como esto, así que tal vez sea una mala idea ...

¿Fue útil?

Solución

Recomiendo encarecidamente el consejo en Blog de Krzysztof y notarías que en tu caso parece que estás 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 la causa. Como tal, una función auxiliar para:

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

Es lo que se requiere.

El enfoque 1 es más claro, pero puede conducir a un uso un poco más detallado, 2 es lo contrario, intercambiando una sintaxis terser por menos claridad.

Tenga en cuenta que las funciones deben ser extremadamente seguras (nunca deberían causar una excepción no relacionada) y no forzar el suministro de datos que son opcionales en ciertos usos razonables.

Al utilizar cualquiera de estos enfoques, facilita la internacionalización del mensaje de error más adelante si es necesario.

Un seguimiento de pila como mínimo le proporciona la función y posiblemente el número de línea, por lo que debe centrarse en proporcionar información que no sea fácil de resolver a partir de eso.

Otros consejos

No voy a restar valor a los consejos 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 tomé prestado en alguna parte, disculpas a quien sea)

<?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()}";
    }
}

Consulte Cómo diseñar jerarquías de excepción en el blog de Krzysztof Cwalina, coautor de " Framework Design Guidelines " ;.

Nunca, nunca confíes en un usuario para "hacer lo correcto" e incluya información para la depuración. Si desea información, debe reunirla usted mismo y almacenarla en un lugar donde sea accesible.

También como se indicó, si es difícil (er) hacer algo, los usuarios evitarán hacerlo, así que de nuevo, no dependan de su buena voluntad y su conocimiento de lo que necesitan enviar.

Este pensamiento implica un método mediante el cual se recopila la información y se registra, lo que implica utilizar var_dump () en alguna parte.

Además, como dijo Mark Harrison, un botón que facilita el envío de un mensaje de error a algún lugar es fantástico para usted y para los usuarios. Les facilita la tarea de informar un error. Usted (como destinatario) obtiene muchos duplicados, pero la información duplicada es mejor que ninguna información.

Por más detalles que añadas, asegúrate y

  • facilita cortar y pegar todo, o
  • tiene un botón que informará el error para ellos
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top