Exceptional Exceptions

PHP comes with several “built-in” exception classes:

  • RuntimeException - occurs when something that conflicts with the runtime of the application happens. Example: A user entering an invalid password could cause a RuntimeException.

  • LogicException - occurs when the program tries to accomplish something impossible. Example: Dividing by zero.

  • InvalidArgumentException - occurs whenever a generic error, usually caused by faulty user input, leads to an illogical condition. Example: User inputs the word “banana” instead of their age. All InvalidArgumentExceptions are also LogicExceptions.

  • DomainException - occurs whenever something happens way outside the range of expected possibilities. Example: Querying a database for the 1,000th record when there are only 500 records could throw a DomainException. All DomainExceptions are also LogicExceptions.

Custom Exceptions

On top of PHP’s built-in function classes, you can also, effortlessly, create your own. The most straightfoward way is to choose one of the built-in classes (usually LogicException or RuntimeException) and extend it:

class SQLException extends DomainException { }

Because of Exception Escalation, custom exceptions do not require any additional code to be useful in determining programming flow. This is true the vast majority of the time.

Exception Escalation

Because of the hierarchical nature of Exceptions, one should catch them in order of most specific to most generic. “Exception” is the most generic and will capture all exceptions.

E.g.

try
{
    fetchSQLRecord($sql);
}
catch (SQLException $e)
{
    echo "

Oops there was a problem with the database

"; error_log("ERROR: SQL failed: $sql"); } // Handle strange stuff, like, maybe Hard drive failure. catch (RuntimeException $e) { echo "

Sorry, we're having technical difficulties.

"; error_log("Runtime Exception: " . $e->getMessage()); } catch (Exception $e) { echo "

Something unexpected happened

"; error_log("Unknown exception: " . $e->getMessage()); }

In this example, if there is a SQL error, the catch(SQLException) code will be executed. If there is a memory error, the catch(RuntimeException) will be executed, and all other exceptions will be caught by the catch (Exception) block.

Handling Specific Exceptional Events

In many instances, even custom exceptions do not offer the finer granularity necessary to respond to particular exceptional events. The mechanisms for handling such events rely on flow controls around the results of Exception::getCode() and Exception::getMessage() functions.