6

我有一个自定义异常(可能在其他自定义异常中进一步扩展)。我的项目需要记录所有发生的 customExceptions(及其所有后代)。我有一个可以记录 customException (以及其他任何东西)的记录器。这样做的一种方法是在异常处理时显式记录异常,如下所示。

try{
    //some exception occur
}
catch(customeException $e)
{
     $log->logException($e);
     $e->showMessage(); // or do anything that we have to do with the error.
}

由于我们正在记录所有 customExceptions,我能想到的另一种方式是更新 customException 构造函数并在构造函数中记录异常。这样,它确保记录了所有 customException。但是,如果我们走这条路,我的问题是:

  1. 如何将记录器注入customException?
  2. 会不会违反SRP原则?
  3. 它会被认为是 OOP 意义上的不良做法,还是这方面的最佳做法是什么?
4

2 回答 2

4

我认为将记录器注入 CustomException 是不对的,因为(正如您所指出的)它会破坏 SRP 并增加异常类的复杂性。

我建议您将 Exception 与 ExceptionHandler 分开。异常类应该只包含关于“什么(和哪里)出了问题”的信息。ExceptionHandler 负责记录异常(并在需要时对异常进行一些其他工作)。

所以你可以设置一个全局的ExceptionHandler(使用set_exception_handlerset_error_handler或者一些基于框架的异常处理机制,比如symfony 的 ExceptionListener),它将捕获所有未处理的异常。

<?php

class ExceptionHandler {
  /**
   * @var Logger
   */
  private $logger;

  public function __construct(Logger $logger)
  {
    $this->logger = $logger;
  }

  public function handle(Throwable $e)
  {
    $this->logger->logException($e);
  }
} 

在应用程序代码中,您仍然可以抛出和捕获异常。我认为有4种常见情况。

完全可恢复的异常

这是处理可恢复异常的一般方法——这种情况下您根本不想失败,但是当这种异常发生时您需要做一些事情。

<?php

try {
  $methodThatThrowsException();
}
catch (DoesNotMatterException $e) {
  // do some stuff and continue the execution
  // note, that this exception won't be logged 
}

可恢复的记录异常

与以前相同,但您要记录此异常。

<?php

try {
  $methodThatThrowsException();
}
catch (NonCriticalExceptionThatShouldBeLogged $e) {
  $this->exceptionHandler->handle($e); // log exception
  // do some stuff and continue the execution
}

“终结器”的不可恢复异常

你想执行一些特定的业务逻辑然后失败。您可以捕获异常,对其进行处理,然后再次抛出它。全局异常处理程序将处理此异常并记录它。

<?php 

try {
  $methodThatThrowsException();
}
catch (CriticalException $e) {
  // do some stuff like cleanup/transaction rollback
  throw $e;
}    

不可恢复的异常

如果您只想记录异常并失败,则可以抛出此异常,全局异常处理程序将捕获并记录它。

<?php

$methodThatThrowsException();

// ExceptionHandler::handle will be executed
于 2018-03-01T09:52:50.097 回答
0

服务可以注入到其他服务中,只要它们是相关的并维护 SRP 或执行一些一般系统的操作,如错误日志记录。但是,异常并不是真正的服务,它应该只关心基于可抛出的异常数据的管理。

我认为登录异常类也是一个问题,因为:

  1. 无法控制要使用的日志类型、警告、错误、关键等。除非你让它变得复杂/复杂
  2. 无法控制是否记录。在某些情况下可能会发生异常,但这是不需要错误处理等的已知情况
  3. 您必须将各种其他日志记录数据传递给异常,这可能有点异味,具体取决于您要记录的数据

在捕获异常时,记录它,然后抛出一个新异常,以便调用者也可以捕获、记录、抛出。在您的应用程序中重复此操作,以便每个需要捕获潜在异常的方法调用,记录并抛出与该类相关的名为自己的异常。

当您到达顶部时,例如控制器,不要抛出而是用漂亮的消息渲染视图。

于 2020-10-08T14:16:12.693 回答