Error handling is a fundamental part of writing reliable, maintainable software. In PHP, exceptions provide a powerful and structured way to deal with errors compared to traditional error reporting mechanisms like trigger_error() or die(). Understanding how to properly use exceptions can make your code cleaner, safer, and easier to debug.
An exception is an object that represents an error or unexpected behavior in your program. When an exception occurs, PHP stops executing the current block of code and looks for a matching catch block to handle the error.
If no handler is found, the script ends with a fatal error, unless you define a global exception handler.
All exceptions in PHP are derived from the built-in Exception class (or Throwable in PHP 7+).
Basic Exception Handling with try and catch
The foundation of exception handling in PHP lies in the try and catch blocks:
try { // Code that may throw an exception $result = divide(10, 0); echo $result; } catch (Exception $e) { // Handle the exception echo "Error: " . $e->getMessage(); } function divide($a, $b) { if ($b === 0) { throw new Exception("Division by zero is not allowed"); } return $a / $b; } // Error: Division by zero is not allowed
Adding Cleanup with finally
Sometimes, you need to release resources, close database connections, or log actions regardless of whether an exception occurs. This is where the finally block shines:
try { $file = fopen("data.txt", "r"); if (! $file) { throw new Exception("File not found"); } // Process the file... } catch (Exception $e) { echo "Caught exception: " . $e->getMessage(); } finally { if ($file) { fclose($file); echo "File closed successfully."; } } // Warning: fopen(data.txt): Failed to open stream: No such file or directory // Caught exception: File not found
The finally block always executes, even if:
Global Exception Handler
Instead of scattering try/catch everywhere, PHP lets you define a global exception handler using set_exception_handler():
set_exception_handler("handleGlobalException"); function handleGlobalException(Throwable $e) { echo "Global handler caught: " . $e->getMessage(); // Log error, send notification, etc. } throw new Exception("Something went wrong!"); // Global handler caught: Something went wrong!
- Why use a global handler?
Nested Exceptions
Sometimes one exception leads to another. For example, a database exception might be wrapped inside a service exception. This is known as nested exceptions.
class ServiceException extends Exception {} try { try { throw new Exception("Database connection failed"); } catch (Exception $e) { throw new ServiceException("User service unavailable", 0, $e); } } catch (ServiceException $se) { echo "Caught: " . $se->getMessage(); echo "Previous: " . $se->getPrevious()->getMessage(); } // Caught: User service unavailable // Previous: Database connection failed
Here:
Multi-Catch Exception Handling
Since PHP 7.1, you can catch multiple exception types in a single catch block:
try { // Some risky operation riskyOperation(); } catch (InvalidArgumentException | RuntimeException $e) { echo "Caught exception of type: " . get_class($e); } catch (Exception $e) { echo "General exception: " . $e->getMessage(); }
- When to use multi-catch?
Source: Orkhan Alishov's notes