PHP Exceptions — Complete Guide to Try, Catch, and Throw
In this tutorial, you will learn about PHP Exceptions. We cover key concepts, practical examples, and best practices to help you master this topic.
PHP exceptions provide an object-oriented approach to error handling using try/catch blocks, allowing controlled error recovery and cleaner code than traditional error functions.
What You'll Learn
By the end of this tutorial, you'll use try/catch/finally blocks, throw exceptions, create custom exception classes, catch multiple exception types, and implement best practices.
Why Exceptions Matter
Exceptions separate error handling code from normal flow, propagate automatically through the call stack, and provide detailed context about what went wrong and where.
Real-World Use
A database wrapper throws exceptions on connection failure, query errors, and validation issues. The controller catches these and returns appropriate HTTP responses without crashing.
Exceptions Learning Path
flowchart LR
A[Errors] --> B[Exceptions]
B --> C[Classes/Objects]
C --> D[Inheritance]
D --> E[Interfaces]
A --> F{You Are Here}
style F fill:#f90,color:#fff
Basic Try/Catch
<?php
try {
$result = 10 / 0;
} catch (DivisionByZeroError $e) {
echo "Caught: " . $e->getMessage();
} finally {
echo "This always runs";
}
Throwing Exceptions
<?php
function findUser(int $id): array {
$users = [1 => ["name" => "Alice"], 2 => ["name" => "Bob"]];
if (!isset($users[$id])) {
throw new InvalidArgumentException("User not found: $id");
}
return $users[$id];
}
try {
$user = findUser(5);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(); // User not found: 5
}
Custom Exception Classes
<?php
class DatabaseException extends RuntimeException {
public function __construct(string $message, int $code = 0, ?Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
}
class UserNotFoundException extends RuntimeException {
public function __construct(int $userId) {
parent::__construct("User #$userId not found", 404);
}
}
try {
throw new UserNotFoundException(42);
} catch (UserNotFoundException $e) {
http_response_code($e->getCode());
echo $e->getMessage();
}
Multiple Catch Blocks
<?php
try {
$file = fopen("config.json", "r");
if (!$file) throw new RuntimeException("Cannot open file");
$content = fread($file, filesize("config.json"));
$data = json_decode($content, flags: JSON_THROW_ON_ERROR);
} catch (RuntimeException $e) {
echo "File error: " . $e->getMessage();
} catch (JsonException $e) {
echo "JSON error: " . $e->getMessage();
} finally {
if (isset($file) && $file) fclose($file);
}
Exception Propagation
<?php
function inner(): void {
throw new RuntimeException("Inner error");
}
function outer(): void {
try {
inner();
} catch (RuntimeException $e) {
throw new RuntimeException("Outer error", 0, $e);
}
}
try {
outer();
} catch (RuntimeException $e) {
echo $e->getMessage(); // Outer error
echo $e->getPrevious()->getMessage(); // Inner error
}
Common Mistakes
1. Catching Too Broad an Exception
Catching Throwable catches everything including system errors. Catch specific exception types.
2. Empty Catch Blocks
Swallowing exceptions without logging or handling hides bugs. At minimum, log the error.
3. Using Exceptions for Control Flow
Exceptions are for exceptional conditions, not regular control flow. Don't throw/catch for expected conditions like validation errors.
4. Not Cleaning Up Resources in Finally
Always close files and database connections in finally blocks to prevent resource leaks.
5. Exposing Exception Details to Users
Exception messages may contain sensitive information. Log the details and show a generic message to users.
Practice Questions
1. What is the base class for all PHP exceptions?
Throwable interface. Error and Exception implement Throwable. Catch Throwable to catch everything.
2. What is the purpose of the finally block?
It always executes after try/catch, regardless of whether an exception was thrown. Used for cleanup.
3. How do you create a custom exception?
Extend the Exception class or a subclass like RuntimeException. Add custom properties and methods as needed.
4. What is exception chaining?
Passing a previous exception to a new exception's constructor, preserving the original error context.
5. Challenge: Create a custom exception hierarchy for a user management system.
<?php
class UserException extends RuntimeException {}
class UserNotFoundException extends UserException {}
class UserValidationException extends UserException {}
class DuplicateEmailException extends UserException {}
try {
// Simulate different error conditions
throw new DuplicateEmailException("Email already registered");
} catch (UserNotFoundException $e) {
http_response_code(404);
} catch (UserValidationException $e) {
http_response_code(400);
} catch (UserException $e) {
http_response_code(500);
}
FAQ
Mini Project: Exception Handler
Build a global exception handler that logs and returns appropriate responses.
<?php
set_exception_handler(function(Throwable $e): void {
$log = sprintf("[%s] %s in %s:%d\n",
date("Y-m-d H:i:s"), $e->getMessage(), $e->getFile(), $e->getLine());
file_put_contents("exceptions.log", $log, FILE_APPEND);
$code = $e->getCode() >= 100 && $e->getCode() < 600 ? $e->getCode() : 500;
http_response_code($code);
header("Content-Type: application/json");
echo json_encode(["error" => $code === 500 ? "Server error" : $e->getMessage()]);
});
throw new RuntimeException("Something broke", 400);
What's Next
PHP Classes Objects PHP Inheritance PHP Interfaces
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro