PHP Error Handling
Errors are inevitable in software — files go missing, database connections fail, unexpected values arrive from users. Proper error handling means anticipating these situations and responding in a controlled way rather than letting the application crash or leak sensitive information. PHP provides several mechanisms for handling errors: traditional error levels, exceptions, and custom error handlers.
PHP Error Types
| Error Type | Severity | Description |
|---|---|---|
| E_ERROR | Fatal | Script stops immediately (memory exhausted, missing method) |
| E_WARNING | Non-fatal | Script continues but something is wrong (file not found) |
| E_NOTICE | Informational | Possible bug (undefined variable, undefined index) |
| E_PARSE | Fatal | Syntax error in the code |
| E_DEPRECATED | Informational | Using a feature that will be removed in a future PHP version |
Controlling Error Display
<?php
// During development — show all errors
ini_set("display_errors", 1);
ini_set("display_startup_errors", 1);
error_reporting(E_ALL);
// In production — hide errors from users, log them instead
// ini_set("display_errors", 0);
// ini_set("log_errors", 1);
// ini_set("error_log", "/path/to/error.log");
// error_reporting(E_ALL);
?>
In production, always log errors rather than displaying them — displaying errors exposes file paths, database names, and other sensitive information to potential attackers.
try / catch / finally — Exception Handling
Exceptions are the modern, object-oriented approach to error handling. Code that might fail is placed inside a try block. If an exception is thrown, execution jumps to the matching catch block. The optional finally block runs regardless of whether an exception occurred.
<?php
function divideNumbers(float $a, float $b): float {
if ($b === 0.0) {
throw new InvalidArgumentException("Division by zero is not allowed.");
}
return $a / $b;
}
try {
echo divideNumbers(10, 2) . "\n"; // 5
echo divideNumbers(10, 0) . "\n"; // Throws exception
} catch (InvalidArgumentException $e) {
echo "Error: " . $e->getMessage();
} finally {
echo "Calculation attempt finished."; // Always runs
}
?>
Catching Multiple Exception Types
<?php
function processFile(string $filename): string {
if (!file_exists($filename)) {
throw new RuntimeException("File not found: $filename");
}
$content = file_get_contents($filename);
if ($content === false || strlen($content) === 0) {
throw new UnexpectedValueException("File is empty: $filename");
}
return $content;
}
try {
$content = processFile("data.txt");
echo "File content: " . $content;
} catch (RuntimeException $e) {
echo "File error: " . $e->getMessage();
} catch (UnexpectedValueException $e) {
echo "Content error: " . $e->getMessage();
} catch (Exception $e) {
// Catch-all for any other exception
echo "Unexpected error: " . $e->getMessage();
}
?>
PHP 8 — Catching Multiple Types in One Catch
<?php
try {
// ... code that might throw
} catch (RuntimeException | InvalidArgumentException $e) {
echo "Caught: " . $e->getMessage();
}
?>
Creating Custom Exceptions
Custom exception classes make error handling more specific and meaningful. They extend PHP's built-in Exception class.
<?php
class DatabaseException extends RuntimeException {
private string $query;
public function __construct(string $message, string $query = "", int $code = 0) {
parent::__construct($message, $code);
$this->query = $query;
}
public function getQuery(): string {
return $this->query;
}
}
class NotFoundException extends RuntimeException {}
class ValidationException extends InvalidArgumentException {
private array $errors;
public function __construct(array $errors) {
parent::__construct("Validation failed.");
$this->errors = $errors;
}
public function getErrors(): array {
return $this->errors;
}
}
// Usage
try {
$errors = ['email' => 'Invalid email', 'password' => 'Too short'];
throw new ValidationException($errors);
} catch (ValidationException $e) {
foreach ($e->getErrors() as $field => $message) {
echo "$field: $message\n";
}
}
?>
Custom Error Handler with set_error_handler()
The set_error_handler() function registers a custom function to handle non-fatal PHP errors.
<?php
function customErrorHandler(int $errno, string $errstr, string $errfile, int $errline): bool {
$message = "[$errno] $errstr in $errfile on line $errline";
error_log($message); // Log the error
if ($errno === E_ERROR) {
echo "A critical error occurred. Please try again later.";
exit(1);
}
return true; // Return true to prevent PHP's default handler from running
}
set_error_handler("customErrorHandler");
// Trigger a notice
$undefined; // E_NOTICE
?>
set_exception_handler() — Global Exception Handler
<?php
function globalExceptionHandler(Throwable $e): void {
// Log the full details
error_log($e->getMessage() . "\n" . $e->getTraceAsString());
// Show a user-friendly message
http_response_code(500);
echo "An unexpected error occurred. Our team has been notified.";
}
set_exception_handler("globalExceptionHandler");
// Any uncaught exception will now be handled by this function
throw new RuntimeException("Something went wrong!");
?>
Key Points
- PHP has different error types (fatal, warning, notice) with different severity levels.
- In production, always log errors and hide them from users; in development, display all errors.
try/catch/finallyis the standard way to handle exceptions in modern PHP.- Use
throwto raise an exception; catch it with the correct exception class in acatchblock. - Create custom exception classes by extending
Exceptionor one of its subclasses. - Register global handlers with
set_error_handler()andset_exception_handler()to catch anything that slips through. - The
finallyblock always runs — use it for cleanup operations like closing files or database connections.
