php catch用法 - 自定義異常消息:最佳實踐




try exception (5)

想知道在創建異常消息時我應該多少努力來強制使用有用的調試信息,或者我應該只是信任用戶提供正確的信息,還是將信息收集推遲到異常處理程序?

我看到很多人都在做他們的例外,例如:

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

或者使用自定義異常擴展默認異常但不會做太多但只更改異常名稱:

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

但這並沒有提供太多的調試信息......並且不會使用錯誤消息強制執行任何格式化。 因此,您可能會產生完全相同的錯誤,產生兩個不同的錯誤消息...例如“數據庫連接失敗”與“無法連接到數據庫”

當然,如果它冒泡到頂部,它將打印堆棧跟踪,這是有用的,但它並不總是告訴我我需要知道的一切,通常我最終不得不開始射擊var_dump()語句來發現出了什麼問題,哪裡......雖然這可能會被一個體面的異常處理程序所抵消。

我開始考慮類似下面的代碼,我需要異常的thrower來提供必要的args來產生正確的錯誤消息。 我想這可能就是這樣:

  • 必須提供最低有用信息
  • 產生一些一致的錯誤消息
  • 異常消息的模板都在一個位置(異常類),因此更容易更新消息...

但我發現缺點是它們更難使用(需要你查找異常定義),因此可能會阻止其他程序員使用提供的異常......

我想對這個想法和一致,靈活的異常消息框架的最佳實踐發表評論。

/**
* @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#

並沒有提到這樣的事情,所以也許這是一個壞主意......


Answers

我強烈推薦Krzysztof博客上的建議,並註意到在你的情況下,你似乎試圖處理他所謂的用法錯誤。

在這種情況下,所需要的不是指示它的新類型,而是關於導致它的更好的錯誤消息。 作為這樣的輔助函數:

  1. 生成要放入異常的文本字符串
  2. 生成整個異常和消息

是什麼需要。

方法1更清晰,但可能導致更冗長的使用,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()}";
    }
}

永遠不要相信用戶“做正確的事”,並包含調試信息。 如果您需要信息,則需要自己收集信息並將其存儲在可訪問的位置。

同樣如上所述,如果做某事很難(呃),用戶將避免這樣做,所以再次,不要依賴他們的善意和他們需要發送的知識。

這種想法暗示了一種收集信息並記錄它的方法,這意味著在某處使用var_dump()。

此外,正如馬克·哈里森所說,一個按鈕可以讓你輕鬆地在某個地方發送錯誤信息對於你和用戶來說都是非常棒的。 它使他們很容易報告錯誤。 您(作為收件人)獲得了大量重複項,但重複信息優於無信息。



不要這樣做 。 提出一個光明的Exception絕對不是正確的做法; 相反,請參閱share 。

不能得到比這更pythonic:

raise Exception("I know python!")

如果您想了解更多信息,請參閱python 的raise語句文檔





php exception