Подтвердить что ты не робот

Пользовательские сообщения об исключении: лучшие практики

Интересно, как много усилий я должен предпринять для форматирования полезной информации отладки при создании сообщений об исключениях, или я должен просто доверять пользователю для предоставления правильной информации или отложить сбор информации до обработчика исключений?

Я вижу много людей, которые делают свои исключения, например:

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

или расширения исключений по умолчанию с пользовательскими исключениями, которые не делают ничего, кроме изменения имени исключения:

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

Но это не дает много информации об отладке... и не приводит к принудительному форматированию с сообщением об ошибке. Таким образом, вы можете получить точно такую ​​же ошибку, производящую два разных сообщения об ошибках... например, "Не удалось подключиться к базе данных" vs "Не удалось подключиться к db"

Конечно, если он пузырится вверх, он будет печатать трассировку стека, что полезно, но это не всегда говорит мне все, что мне нужно знать, и обычно мне приходится начинать стрельбу из var_dump() чтобы обнаружить, что пошло не так, и где... хотя это может быть несколько компенсировано достойным обработчиком исключений.

Я начинаю думать о чем-то вроде кода ниже, где мне требуется метатор исключения для предоставления необходимых аргументов для создания правильного сообщения об ошибке. Я думаю, что это может быть способ сделать это:

  • Минимальный уровень полезной информации должен быть предоставлен
  • Производит несколько согласованных сообщений об ошибках
  • Шаблоны для сообщений об исключениях в одном месте (классы исключений), поэтому проще обновлять сообщения...

Но я вижу недостаток в том, что их труднее использовать (требуется искать определение исключения) и, таким образом, может препятствовать другим программистам использовать предоставленные исключения...

Я хотел бы прокомментировать эту идею и передовые методы для последовательной гибкой структуры сообщений исключений.

/**
* @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();
    }
}

Затем используется как:

// 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
}

и мы можем сделать что-то вроде nl2br в специальном обработчике исключений, чтобы сделать что-то приятное для вывода html.

Читал: http://msdn.microsoft.com/en-us/library/cc511859.aspx#

И не упоминается ничего подобного, так что, может быть, это плохая идея...

4b9b3361

Ответ 1

Я настоятельно рекомендую совет блог Krzysztof и заметьте, что в вашем случае вы, похоже, пытаетесь разобраться с тем, что он называет ошибками использования.

В этом случае требуется не новый тип, чтобы указать его, но лучшее сообщение об ошибке, вызвавшее его. Как таковая вспомогательная функция для:

  • генерировать текстовую строку для размещения в исключении
  • генерирует все исключение и сообщение

Это то, что требуется.

Подход 1 более ясный, но может привести к немного более подробному использованию, 2 - наоборот, торгуя синтаксисом терминатора для меньшей ясности.

Обратите внимание, что функции должны быть чрезвычайно безопасными (они никогда не должны вызывать самозависимое исключение), а не принуждать предоставлять данные, которые являются необязательными в определенных разумных целях.

Используя любой из этих подходов, вы упростите интернационализацию сообщения об ошибке позже, если это необходимо.

Трассировка стека по минимуму дает вам функцию и, возможно, номер строки, поэтому вам следует сосредоточиться на предоставлении информации, которая нелегко выработать из этого.

Ответ 2

Я не буду отвлекаться от рекомендаций относительно блога Krzysztof, но вот простой способ создания пользовательских исключений - это простой способ.

Пример:

<?php
   require_once "CustomException.php";
   class SqlProxyException extends CustomException {}

   throw new SqlProxyException($errorMsg, mysql_errno());     
?>

Код, лежащий в основе этого (который я где-то заимствовал, приношу извинения кому бы то ни было)

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

Ответ 4

Никогда, никогда не доверяйте пользователю "делать правильные вещи" и включайте информацию для отладки. Если вам нужна информация, вам нужно собрать ее самостоятельно и сохранить ее где-нибудь там, где она доступна.

Также, как указано, если это сложно (er) что-то сделать, пользователи избегают этого делать, поэтому снова не зависят от их доброй воли и их знаний о том, что им нужно отправить.

Это мышление подразумевает метод, с помощью которого вы собираете информацию и регистрируете ее, что подразумевает использование var_dump() где-то.

Кроме того, как сказал Марк Харрисон, кнопка, облегчающая отправку сообщения об ошибке где-то, является фантастикой для вас и для пользователей. Это позволяет им сообщать об ошибке. Вы (как получатель) получаете много дубликатов, но дублировать информацию лучше, чем никакой информации.

Ответ 5

Как много подробностей вы добавляете, обязательно и

  • упростить вырезание и вставить все это, или
  • есть кнопка, которая сообщит об ошибке для них