DEV Community

sebk69
sebk69

Posted on

Exceptions good practices

How work exceptions

A php exception is a class which inherits the \Exception class.

The following code will interrupt the process and send the exception class to caller.

throw new \Exception('This is an exception')
Enter fullscreen mode Exit fullscreen mode

The caller can manage teh exception in a try/catch block to define the behavior to adopt in that case.

try {
    myFunction();
} catch(\Exception $e) {
    sendExceptionMessage($e->getMessage());
}
Enter fullscreen mode Exit fullscreen mode

If the caller don't manage exception, the exception will be thrown to his caller, and so on...

If no one catch the exception, php will generate a fatal error (useful in some cases).

Principle and benefit of inheritance

For example, we will create an exception :

class CustomerNotFoundException extends \Exception {}
Enter fullscreen mode Exit fullscreen mode

We have two ways to catch exceptions :

findCustomer(int $id)
{
    $customers = $this->orm->findCustomers(['id' => $id]);

    if (count($customers) == 0) {
        throw new CustomerNotFoundException('Unknonw customer');
    }

    if (count($cutomers) > 1) {
        throw new \LogicException('Duplicate customers');
    }

    return $cutomers[0];

}

try {
    findCustomer(1);
} catch(CustomerNotFoundException $e) {
    echo "No customer with this id";
} catch(\Exception $e) {
    echo 'An error occured !';
}
Enter fullscreen mode Exit fullscreen mode

In this example, on can see the inheritance can complexify the exceptions management in order to manage more than one way.

Good practices

Never use \Exception when throwing exception, always use a specific exception class

If we use \Exception, it will be impossible to target a catch and probably catch exceptions in a child function/method without wanting it.

Even if this not seem to be problematic actually, we don't know how the code will evolve.

Use a structure on inheritance

When we create an exception, alway use an exception class regrouping all exceptions of your perimeter. This allow to target exceptions of you perimeter and let system to manage other exceptions.

class OrmException extends \Exception {}
class NotFoundException extends OrmException {}
class SqlFailException extends OrmException {}

monClient()
{
    return $orm->findOneCustomer(1);
}

try {
    monClient();
} catch(NotFoundException) {
    echo "You have no customer";
} catch(OrmException) {
    echo "Orm error occured"
} catch(\Exception) {
    echo "Fatal exception occured"
}
Enter fullscreen mode Exit fullscreen mode

Grouping exception in subfoler structure

This way to manage exceptions will generate a lot of exception classes, so, it is required to regroup them.

The principle is to thought every application perimeters in modules :

  • Entity
    • Bean
      • Customer
    • Exception
      • BadBirthDayDateException
      • CustomerException
      • EmptyFirstNameException
  • UseCase
    • BirthdayMailingUseCase
    • EventWinnedUserCase
    • Exception
      • EmailNotSentException
      • MailingUseCaseException

Top comments (0)