问题
I have a custom exception (which is further extended in may other custom exceptions). My project requires log all the customExceptions (and all of its decendents) that occurs. I have a logger that can log customException (and anything else). One of the way of doing so is explicitly log the exception whenever it is being handled as follows.
try{
//some exception occur
}
catch(customeException $e)
{
$log->logException($e);
$e->showMessage(); // or do anything that we have to do with the error.
}
Since we are logging all the customExceptions, the other way I can think of, updating the customException constructor and log the exception right there inside the constructor. In that way, it ensure that all the customException is logged. However, if we go down to this path, my questions is:
- How to inject the logger to the customException?
- Will it be against the SRP principle?
- Will it be consider bad practice in OOP sense or what is the best practice on this?
回答1:
I think that injecting logger into the CustomException is not right, cause (as you pointed) it breaks SRP and increase the complexity of your exceptions classes.
I'll suggest you to separate Exception from ExceptionHandler. Exception class should only contain information about "what (and where) went wrong". ExceptionHandler is responsible for logging exception (and doing some other work with exception if needed).
So you can setup one global ExceptionHandler
(using set_exception_handler and set_error_handler or some framework-based exception handling mechanism like symfony's ExceptionListener), that will catch all unhandled exceptions.
<?php
class ExceptionHandler {
/**
* @var Logger
*/
private $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function handle(Throwable $e)
{
$this->logger->logException($e);
}
}
In application code you can still throw and catch exceptions. I think there are 4 common situations.
Fully recoverable exceptions
This is general way for handling recoverable exceptions – such situations when you don't want to fail at all, but you need to do something when such exception occurs.
<?php
try {
$methodThatThrowsException();
}
catch (DoesNotMatterException $e) {
// do some stuff and continue the execution
// note, that this exception won't be logged
}
Recoverable logged exception
The same as previous, but you want to log this exception.
<?php
try {
$methodThatThrowsException();
}
catch (NonCriticalExceptionThatShouldBeLogged $e) {
$this->exceptionHandler->handle($e); // log exception
// do some stuff and continue the execution
}
Non-recoverable exceptions with "finalizer"
You want to execute some specific business logic and then fail. You can catch the exception, process it and then throw it again. Global exception handler will handle this exception and log it.
<?php
try {
$methodThatThrowsException();
}
catch (CriticalException $e) {
// do some stuff like cleanup/transaction rollback
throw $e;
}
Non-recoverable exceptions
If you want to just log the exception and fail, you can just throw this exception and global exception handler will catch and log it.
<?php
$methodThatThrowsException();
// ExceptionHandler::handle will be executed
来源:https://stackoverflow.com/questions/49038329/best-practice-of-log-custom-exceptions-in-php