Handling Runtime Exceptions in PHP
What is an Exception?
Section titled “What is an Exception?”Think of an exception as a signal that something unexpected happened in your code. Just like when you’re driving and encounter a roadblock: you need to find an alternative route.
In programming terms:
- An exception is an event that occurs during program execution that disrupts the normal flow,
- Instead of your program crashing, exceptions allow you to handle errors gracefully,
- You can throw exceptions when problems occur and catch them to handle the situation.
Types of Exceptions
Section titled “Types of Exceptions”PHP offers two main categories of exceptions:
-
Built-in Exceptions: PHP comes with ready-to-use exceptions for common problems:
Exception- The base exception classInvalidArgumentException- When wrong data is passed to a functionRuntimeException- When something goes wrong during executionPDOException- Database-related errors
-
Custom Exceptions: You can create your own specialized exceptions for specific situations in your application by extending the base
Exceptionclass.
Basic Exception Handling
Section titled “Basic Exception Handling”Exception handling follows a simple pattern: try to do something, and if it fails, catch the problem.
The Try-Catch Pattern
Section titled “The Try-Catch Pattern”Think of it like this:
- Try: “Let me attempt this risky operation”
- Catch: “If something goes wrong, here’s how I’ll handle it”
try { // Code that might fail $result = someRiskyFunction(); echo "Success: $result";} catch (Exception $e) { // What to do if it fails echo 'Something went wrong: ' . $e->getMessage();}Throwing Your Own Exceptions
Section titled “Throwing Your Own Exceptions”When you detect a problem in your code, you can “throw” an exception to signal the issue:
function divide($a, $b) { // Check for invalid input if ($b === 0) { throw new Exception("Cannot divide by zero!"); } return $a / $b;}
// Using the function with exception handlingtry { echo divide(10, 2); // Works fine: outputs 5 echo divide(10, 0); // This will throw an exception} catch (Exception $e) { echo "Error: " . $e->getMessage();}Custom Exceptions
Section titled “Custom Exceptions”Custom exceptions help you create meaningful error categories for your application. Instead of using generic exceptions, you can create specific ones that make your code more readable.
Why use custom exceptions?
- More descriptive error handling
- Easier to catch specific types of errors
- Better code organization
// Create meaningful exception namesclass InvalidEmailException extends Exception {}class UserNotFoundException extends Exception {}class InsufficientFundsException extends Exception {}
// Example usagefunction validateEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new InvalidEmailException("Invalid email format: $email"); } return true;}
try { validateEmail("not-an-email");} catch (InvalidEmailException $e) { echo "Email validation failed: " . $e->getMessage();} catch (Exception $e) { echo "Something else went wrong: " . $e->getMessage();}The Finally Block
Section titled “The Finally Block”The finally block is like a cleanup crew. It always runs, whether an exception occurred or not.
When to use finally:
- Closing files or database connections
- Cleaning up temporary resources
- Logging operations
$file = null;try { $file = fopen('data.txt', 'r'); // Read file content $content = fread($file, 1000); echo $content;} catch (Exception $e) { echo "Error reading file: " . $e->getMessage();} finally { // Always close the file, even if an error occurred if ($file) { fclose($file); echo "File closed successfully."; }}Nested Try-Catch Blocks
Section titled “Nested Try-Catch Blocks”Sometimes you need layers of error handling. Nested try-catch blocks let you handle different types of problems at different levels. For example, processing user input and saving it to a database may throw exceptions at different stages.
function saveUserData($data) { try { // Validate input — throws if name is empty if (empty($data['name'])) { throw new InvalidArgumentException("Name cannot be empty"); }
try { // Database operation — can fail independently if ($data['name'] == 'error') { throw new RuntimeException("Database error occurred"); } echo "User data saved successfully\n"; } catch (RuntimeException $e) { echo "Database problem: " . $e->getMessage() . "\n"; }
} catch (InvalidArgumentException $e) { echo "Validation failed: " . $e->getMessage() . "\n"; }}
// Test with valid and invalid inputsaveUserData(['name' => 'John']); // "User data saved successfully"saveUserData(['name' => 'error']); // "Database problem: Database error occurred"saveUserData(['name' => '']); // "Validation failed: Name cannot be empty"Best Practices for Exception Handling
Section titled “Best Practices for Exception Handling”-
Keep it simple: Don’t over-nest try-catch blocks. If you have more than 2-3 levels, consider refactoring your code.
-
Be specific: Catch specific exceptions instead of generic ones. This makes debugging much easier.
// Goodcatch (InvalidArgumentException $e) { /* handle */ }catch (DatabaseException $e) { /* handle */ }// Less helpfulcatch (Exception $e) { /* handle everything the same way */ } -
Always log errors: Keep a record of what went wrong for debugging later.
catch (Exception $e) {error_log("Error in function X: " . $e->getMessage());// Then handle the error appropriately} -
Fail gracefully: Show user-friendly messages, not technical error details.
catch (DatabaseException $e) {error_log($e->getMessage()); // Log the technical detailsecho "Sorry, we're having trouble saving your data right now."; // User-friendly message} -
Don’t ignore exceptions: If you can’t handle an exception properly, re-throw it so something else can deal with it.