【问题标题】:organizing technical and user-facing error messages in php在 php 中组织技术和面向用户的错误消息
【发布时间】:2010-01-11 20:39:42
【问题描述】:

我在组织两个交互类的错误消息时遇到了一些问题。一个对象具有“错误”的状态,即出现问题或意外发生,但情况仍然可以挽救。我不想使用异常,1. 因为它们只有一个用于消息的字符串,2. 因为我想在错误之后访问对象。最起码,我想利用它的一些get()方法,在异常之后构造一个有用的错误信息!

最后,我想传达两条信息:一条是作为编码员的我自己,即出现了问题。该字符串将包含文件、行、函数/方法、参数和结果的技术细节。显然,我不想向用户显示这个,所以我想向用户显示另一串错误消息(“找不到那个电子邮件地址”之类的东西)。

所以我想到构建一个错误消息数组,它可以使用异常中的错误代码或状态代码作为各种消息的键。 (虽然如果我这样做,我在哪里存储消息数组?)另一个选择可能是创建一个错误状态对象。

有没有类似“错误模式”的东西,类似于设计模式?

【问题讨论】:

    标签: php exception error-handling


    【解决方案1】:

    例外确实是您的最佳选择,它们会满足您的要求。甚至多条消息也是可能的,因为异常只是您可以扩展的类。您可以将导致异常的对象传递给所述异常。

    <?php
    class ExampleException extends Exception {
      private $secondMessage;
      private $objectThatCausedIt;
      public function __construct( $secondMessage, $objectThatCausedIt ) {
        parent::__construct(
          "Descriptive message for developer",
          // error code for this type of error
          1000 );
        $this->secondMessage = $secondMessage;
        $this->objectThatCausedIt = $objectThatCausedIt;
      }
      public function getSecondMessage() {
        return $this->secondMessage;
      }
      public function getObjectThatCausedIt() {
        return $this->objectThatCausedIt;
      }
    }
    
    class Example {
      public function causeException() {
        throw new ExampleException( "Second Message", $this );
      }
    }
    

    现在您只需使用该类并将可能引发异常的调用包装在 try-catch 块中。

    <?php
    $example = new Example();
    try {
      $example->causeException();
    }
    catch ( ExampleException $e ) {
      // kind of pointless here, just an illustration
      // get object that caused it and do something with it.
      dump_and_log_function( $e->getObjectThatCausedIt() );
      // or just use $example, which is still "alive"
      // and references the same instance
      dump_and_log_function( $example );
    }
    

    扩展异常的好处是您还可以获得堆栈回溯。回溯包含异常发生在哪个文件、行和函数中的信息。您还可以访问错误代码、消息等。我建议您阅读有关异常 (http://php.net/manual/en/class.exception.php) 的 PHP 文档以获取更多信息。

    关于错误消息和日志记录,我通常使用单例类。单例类只有一个自身实例(以防你不知道)。这是一个非常简单的例子:

    <?php
    class Log {
      private $logFile;
      private static $instance;
      /* Log instances may only be constructed in Log::getInstance */
      private function __construct() {
        $this->logFile = fopen( "path/to/log/file", "a" );
      }
      public logMessage( $message ) {
        fwrite( $this->logFile, $message );
      }
      public static getInstance() {
        if ( !self::$instance ) self::$instance = new self();
        return self::$instance;
      }
    }
    

    现在回到异常处理 throw-catch 块,你可以把它改成这样:

    <?php
    $example = new Example();
    try {
      $example->causeException();
    }
    catch ( ExampleException $e ) {
      // log developer message and backtrace
      Log::getInstance()->logMessage( $e->getMessage() );
      Log::getInstance()->logMessage( $e->getTraceAsString() );
      // or more compact by casting to string
      Log::getInstance()->logMessage( (string)$e );
      // and now print error for users
      echo "<p>An Error has occured: {$e->getSecondMessage()}</p>";
    }
    

    您可以使 Log 类具有包含消息数组的属性,而不是立即回显错误消息。然后,您可以稍后在视图脚本中一次性列出它们。您还可以使 logMessage 方法将消息存储在会话中,以便在刷新后显示它们(只是不要忘记清除会话中的消息,否则它们将一遍又一遍地显示;-)。

    【讨论】:

    • 多么棒的第一个答案。欢迎来到 SO!
    • 好吧,10 年后单身人士看起来不再那么好了。现在你有了紧耦合。您将如何测试该代码?您总是依赖于 Log 的非常特殊的实现,它总是写入磁盘!例如,您不能模拟它,并且很难使用不同的日志记录方式,具体取决于它是 Web 还是控制台、cron 或消息传递工作者。我建议使用一些依赖注入。
    【解决方案2】:

    我不想使用异常,1。 因为它们只有一个字符串 对于消息,以及 2. 因为我想要 错误后访问对象。 至少,我想使用一些 它的 get() 方法来构造一个 后有用的错误信息 例外!

    您可以创建自己的异常类,也可以扩展 PHP 的异常类,添加您需要的支持。但是,可能您可以有两个设置,开发人员和客户端,其中客户端错误会显示,而开发人员错误不会转到日志文件或其他内容。

    其中,转换为两种自定义异常类型(尽管您可以有更多,我说的是两个不同的基类)。

    【讨论】:

    • 但是如果我使用异常,那不是在抛出异常后使对象不可用吗?我想在那之后我可能仍想使用它,但也许我可以说服自己放弃它。
    • 不,你可以“捕捉”异常,记录它,无论如何,决定是继续还是退出。您拥有所有的灵活性。
    • 我一直在做一些测试,似乎异常确实会破坏对象:getMessage(), "
      \n";回声 $objExceptor->test() 。 "
      \n"; ?> 得到了这个结果: 捕获异常:我除外!
      致命错误:在第 20 行调用非对象上的成员函数 test()。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 2014-05-28
    • 2020-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多