Error Handling and Logging
40 minError handling is essential for building robust PHP applications that gracefully handle failures and provide meaningful feedback. PHP provides multiple error handling mechanisms: exceptions (try-catch blocks), error reporting functions, custom error handlers, and logging. Understanding when and how to use each mechanism helps you build applications that fail gracefully and provide useful debugging information. Good error handling improves user experience and makes debugging easier.
Exceptions are the modern way to handle errors in PHP. They're thrown with `throw` and caught with `try-catch` blocks. Exceptions can be custom classes extending the base `Exception` class, enabling you to create domain-specific error types. The `finally` block (PHP 5.5+) always executes, useful for cleanup. Exception handling allows you to catch errors at appropriate levels and handle them appropriately. Understanding exceptions helps you write robust, maintainable code.
PHP's error reporting system includes different error levels: E_ERROR (fatal), E_WARNING (non-fatal), E_NOTICE (informational), E_PARSE (syntax), E_DEPRECATED (deprecated features), and more. Error reporting can be configured with `error_reporting()` and `ini_set()`. In production, display errors should be off, and errors should be logged. Understanding error levels helps you configure appropriate error handling for development and production.
Custom error handlers enable you to handle errors programmatically. The `set_error_handler()` function registers a custom function to handle errors. Custom handlers can log errors, send notifications, format error messages, and decide whether to continue execution. Custom exception handlers (`set_exception_handler()`) catch uncaught exceptions. Understanding custom handlers helps you implement centralized error handling and logging.
Logging is crucial for debugging production issues and monitoring applications. PHP's `error_log()` function writes to error logs. You can log to files, system logs, or email. Custom logging classes provide more control over log format, levels, rotation, and destinations. Logging should include context (timestamp, level, message, file, line, stack trace) for effective debugging. Understanding logging helps you monitor applications and debug issues effectively.
Best practices include using exceptions for error handling (not just errors), logging errors with sufficient context, displaying user-friendly error messages (not technical details), handling errors at appropriate levels, and testing error paths. Error handling should be consistent across the application. Understanding error handling enables you to build robust, maintainable PHP applications that handle failures gracefully.
Key Concepts
- Exceptions are the modern way to handle errors in PHP.
- try-catch blocks catch and handle exceptions.
- Custom error handlers enable programmatic error handling.
- Logging is essential for debugging and monitoring.
- Error reporting should be configured differently for development and production.
Learning Objectives
Master
- Using try-catch blocks for exception handling
- Creating custom exception classes
- Implementing custom error handlers
- Setting up logging for debugging and monitoring
Develop
- Error handling and defensive programming thinking
- Understanding error handling strategies
- Designing robust, fault-tolerant applications
Tips
- Use exceptions for error handling, not just errors.
- Log errors with sufficient context (timestamp, level, message, stack trace).
- Display user-friendly error messages, not technical details.
- Handle errors at appropriate levels—don't catch everything at the top level.
Common Pitfalls
- Not handling exceptions, causing application crashes.
- Displaying technical error messages to users, exposing sensitive information.
- Not logging errors, making debugging impossible.
- Catching exceptions too broadly, hiding real problems.
Summary
- Exceptions provide modern, structured error handling.
- try-catch blocks catch and handle exceptions appropriately.
- Custom error handlers enable centralized error handling.
- Logging is essential for debugging and monitoring.
- Understanding error handling enables robust PHP applications.
Exercise
Implement comprehensive error handling and logging system.
<?php
// Custom error handler
function customErrorHandler($errno, $errstr, $errfile, $errline) {
$errorType = [
E_ERROR => 'ERROR',
E_WARNING => 'WARNING',
E_PARSE => 'PARSE',
E_NOTICE => 'NOTICE',
E_CORE_ERROR => 'CORE_ERROR',
E_CORE_WARNING => 'CORE_WARNING',
E_USER_ERROR => 'USER_ERROR',
E_USER_WARNING => 'USER_WARNING',
E_USER_NOTICE => 'USER_NOTICE',
E_STRICT => 'STRICT',
E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
E_DEPRECATED => 'DEPRECATED',
E_USER_DEPRECATED => 'USER_DEPRECATED'
];
$type = $errorType[$errno] ?? 'UNKNOWN';
$message = "[$type] $errstr in $errfile on line $errline";
// Log error
error_log($message . PHP_EOL, 3, 'error.log');
// Display user-friendly message in production
if (ini_get('display_errors')) {
echo "<div style='color: red; padding: 10px; border: 1px solid red;'>";
echo "An error occurred. Please check the error log for details.";
echo "</div>";
}
return true;
}
// Set custom error handler
set_error_handler('customErrorHandler');
// Custom exception class
class DatabaseException extends Exception {
public function __construct($message, $code = 0, Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
public function getDetailedMessage() {
return "Database Error: " . $this->getMessage() .
" (Code: " . $this->getCode() . ")";
}
}
// Logging class
class Logger {
private $logFile;
public function __construct($logFile = 'app.log') {
$this->logFile = $logFile;
}
public function log($level, $message, $context = []) {
$timestamp = date('Y-m-d H:i:s');
$contextStr = !empty($context) ? ' ' . json_encode($context) : '';
$logEntry = "[$timestamp] [$level] $message$contextStr" . PHP_EOL;
file_put_contents($this->logFile, $logEntry, FILE_APPEND | LOCK_EX);
}
public function info($message, $context = []) {
$this->log('INFO', $message, $context);
}
public function error($message, $context = []) {
$this->log('ERROR', $message, $context);
}
public function warning($message, $context = []) {
$this->log('WARNING', $message, $context);
}
}
// Usage example
$logger = new Logger();
try {
// Simulate database operation
$pdo = new PDO("mysql:host=localhost;dbname=nonexistent", "user", "pass");
} catch (PDOException $e) {
$logger->error("Database connection failed", [
'error' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine()
]);
throw new DatabaseException("Failed to connect to database", 500, $e);
}
// Test error handling
$logger->info("Application started", ['version' => '1.0.0']);
$logger->warning("Deprecated function called", ['function' => 'mysql_connect']);
// Trigger a warning
$undefinedVariable = $undefinedVariable + 1;