php 自定义异常消息:最佳实践

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/628408/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 23:18:56  来源:igfitidea点击:

Custom Exception Messages: Best practices

phpexception

提问by timoxley

Wondering how much effort I should go to forcing useful debugging information when creating exception messages, or should I just trust the user to supply the right info, or defer the information gathering to an exception handler?

想知道在创建异常消息时我应该付出多少努力来强制使用有用的调试信息,或者我应该相信用户提供正确的信息,还是将信息收集推迟到异常处理程序?

I see a lot of people people doing their exceptions like:

我看到很多人在做他们的例外,比如:

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

or extending the default exceptions with custom exceptions that don't do much but change the name of the exception:

或者使用自定义异常扩展默认异常,这些自定义异常不会做太多但会更改异常名称:

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

But this doesn't supply much debugging info... and doesn't enforce any kind of formatting with the error message. So you could end up with exactly the same error producing two different error messages... eg "Database connection failed" vs "Could not connect to db"

但这并没有提供太多的调试信息......并且不会对错误消息强制执行任何格式。所以你最终可能会得到完全相同的错误,产生两个不同的错误消息......例如“数据库连接失败”与“无法连接到数据库”

Sure, if it bubbles to the top, it'll print the stack trace, which is useful, but it doesn't always tell me everything I need to know and usually I end up having to start shooting off var_dump() statements to discover what went wrong and where... though this could be somewhat offset with a decent exception handler.

当然,如果它冒泡到顶部,它会打印堆栈跟踪,这很有用,但它并不总是告诉我我需要知道的一切,通常我最终不得不开始拍摄 var_dump() 语句来发现出了什么问题,在哪里......虽然这可能会被一个体面的异常处理程序所抵消。

I'm starting to think about something like the code below, where I requirethe thrower of the exception to supply necessary args to produce the correct error message. I'm thinking this might be the way to go in that:

我开始考虑类似下面的代码,我需要异常的抛出者提供必要的参数来产生正确的错误消息。我想这可能是这样做的方法:

  • Minimum level of useful information must be supplied
  • Produces somewhat consistent error messages
  • Templates for exception messages all in the one location (exception classes), so easier to update the messages...
  • 必须提供最低级别的有用信息
  • 产生一些一致的错误信息
  • 异常消息的模板都在一个位置(异常类),因此更容易更新消息......

But I see the downside being that they are harder to use (requires you look up exception definition), and thus might discourage other programmers from using supplied exceptions...

但我认为缺点是它们更难使用(需要您查找异常定义),因此可能会阻止其他程序员使用提供的异常......

I'd like some comment on this idea, & best practices for a consistent, flexible exception message framework.

我想对这个想法和一致、灵活的异常消息框架的最佳实践发表一些评论。

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

Then used like:

然后像这样使用:

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

and we might do something like a nl2br in a custom exception handler to make things nice for html output.

我们可能会在自定义异常处理程序中执行类似 nl2br 之类的操作,以使 html 输出变得更好。

Been reading: http://msdn.microsoft.com/en-us/library/cc511859.aspx#

一直在阅读:http: //msdn.microsoft.com/en-us/library/cc511859.aspx#

And there is no mention of anything like this, so maybe it's a bad idea...

并且没有提到这样的事情,所以也许这是一个坏主意......

采纳答案by ShuggyCoUk

I strongly recommend the advice on Krzysztof's blogand would note that in your case you seem to be trying to deal with what he calls Usage Errors.

我强烈推荐Krzysztof 博客上的建议,并会注意到在您的情况下,您似乎正在尝试处理他所谓的使用错误。

In this case what is required is not a new type to indicate it but a better error message about what caused it. As such a helper function to either:

在这种情况下,需要的不是指示它的新类型,而是关于导致它的原因的更好的错误消息。作为这样的辅助函数:

  1. generate the textual string to place into the exception
  2. generate the whole exception and message
  1. 生成文本字符串以放入异常中
  2. 生成整个异常和消息

Is what is required.

是什么要求。

Approach 1 is clearer, but may lead to a little more verbose usage, 2 is the opposite, trading a terser syntax for less clarity.

方法 1 更清晰,但可能会导致使用更冗长,方法 2 正好相反,用更简洁的语法来降低清晰度。

Note that the functions must be extremely safe (they should never, ever cause an unrelated exception themselves) and not force the provision of data that is optional in certain reasonable uses.

请注意,这些函数必须非常安全(它们自己永远不应该引起不相关的异常)并且不强制提供在某些合理使用中是可选的数据。

By using either of these approaches you make it easier to internationalise the error message later if required.

通过使用这两种方法中的任何一种,您可以更轻松地在以后根据需要将错误消息国际化。

A stack trace at a minimum gives you the function, and possibly the line number, thus you should focus on supplying information that is not easy to work out from that.

堆栈跟踪至少为您提供函数,可能还有行号,因此您应该专注于提供不容易从中计算出来的信息。

回答by Orwellophile

I won't detract from the advise regarding Krzysztof's blog, but here is a dead-easy way to create custom exceptions.

我不会贬低有关 Krzysztof 博客的建议,但这里有一种创建自定义异常的简单方法。

Example:

例子:

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

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

The code behind that (which I borrowed somewhere, apologies to whomever that was)

背后的代码(我从某处借来的,向任何人道歉)

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

回答by John Saunders

See How to Design Exception Hierarchieson the blog of Krzysztof Cwalina, a coauthor of "Framework Design Guidelines".

请参阅“框架设计指南”的合著者 Krzysztof Cwalina 的博客上的如何设计异常层次结构

回答by Matthew Farwell

Never, ever trust a user to 'do the right thing', and include information for debugging. If you want information, you need to gather it yourself and store it somewhere where its accessible.

永远不要相信用户会“做正确的事”,并包含用于调试的信息。如果您需要信息,则需要自己收集信息并将其存储在可以访问的地方。

Also as stated, if it's hard(er) to do something, the users will avoid doing it, so again, don't depend on their goodwill and their knowledge of what they need to send.

同样如上所述,如果做某事很困难(呃),用户将避免这样做,所以同样,不要依赖他们的善意和他们对需要发送的内容的了解。

This thinking implies a method by which you collect the information and log it, which implies using var_dump() somewhere.

这种想法意味着一种收集信息并记录信息的方法,这意味着在某处使用 var_dump()。

Also, as said by Mark Harrison, a button which makes it easy to send an error message somewhere is fantastic for you and for the users. It makes it easy for them to report an error. You (as the recipient) get a lot of duplicates, but duplicate information is better than no information.

此外,正如马克哈里森所说,一个可以轻松向某处发送错误消息的按钮对您和用户来说都很棒。这使他们很容易报告错误。您(作为收件人)会收到很多重复信息,但重复信息总比没有信息要好。

回答by Mark Harrison

However much detail you add, be sure and either

无论您添加多少细节,请确保

  • make it easy to cut and paste the whole thing, or
  • have a button that will report the error for them
  • 使剪切和粘贴整个内容变得容易,或者
  • 有一个按钮可以为他们报告错误