我认为将记录器注入 CustomException 是不对的,因为(正如您所指出的)它会破坏 SRP 并增加异常类的复杂性。
我建议您将 Exception 与 ExceptionHandler 分开。异常类应该只包含关于“什么(和哪里)出了问题”的信息。ExceptionHandler 负责记录异常(并在需要时对异常进行一些其他工作)。
所以你可以设置一个全局的ExceptionHandler
(使用set_exception_handler和set_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