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
  • The try block contains code that might throw an exception.
  • The throw keyword creates an exception object.
  • The catch block intercepts the exception and allows you to handle it gracefully.

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:

  • An exception is thrown
  • The script returns early
  • The catch block doesn't exist

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?

  • Ensures uncaught exceptions are handled gracefully;
  • Provides a centralized place for logging or displaying error messages;
  • Useful for production applications to avoid exposing raw errors to users;

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:

  • The ServiceException is thrown after catching a database error;
  • The original exception is passed as the third argument ($previous);
  • This allows you to preserve the full error chain for debugging;

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?

  • When different exceptions should be handled in the same way;
  • Helps reduce duplicate code;
  • Keeps error handling logic clean;

Source: Orkhan Alishov's notes