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

StackOverflow https://stackoverflow.com/questions/628408

  •  06-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

Конечно, если он всплывет наверх, он напечатает трассировку стека, что полезно, но он не всегда говорит мне все, что мне нужно знать, и обычно мне приходится начинать стрелять с помощью операторов 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#

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

Это было полезно?

Решение

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

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

  1. сгенерировать текстовую строку для помещения в исключение
  2. сгенерировать все исключение и сообщение

Есть то, что требуется.

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

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

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

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

Другие советы

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

Пример:

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

Видеть Как создавать иерархии исключений в блоге Кшиштофа Цвалины, соавтора «Руководства по проектированию фреймворков».

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

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

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

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

Сколько бы деталей вы ни добавили, будьте уверены, и либо

  • чтобы было легко вырезать и вставлять все это целиком, или
  • есть кнопка, которая сообщит им об ошибке
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top