Reputation: 1801
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:
Upvotes: 8
Views: 2684
Reputation: 4804
Services can be injected into other services as long as they are relevant and maintain SRP or do something general systemy like error logging. However, an exception isn't really a service, and it should only be concerned with managing the exception data based on being throwable.
I think logging in an exception class is also a problem due to:
At the point of catching an exception, log it, then throw a new one so the caller can also catch, log, throw. Repeat this throughout your app so every thinga method calls that needs to catch a potential exception, logs and throws it's own exception named relevant to that class.
When you get to the top, e.g. a controller, don't throw but render the view with a nice message.
Upvotes: 0
Reputation: 2287
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.
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
}
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
}
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;
}
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
Upvotes: 6