
PHP Error Handling and Logging: A Comprehensive Guide to Robust Applications
Understanding PHP Error Types and Their Proper Handling
PHP provides several error types that require different handling approaches. The most common categories include fatal errors, recoverable errors, warnings, and notices. Each type should be managed according to its severity and impact on application flow.
// Example of proper error type handling
try {
// Code that might throw an exception
$result = riskyOperation();
} catch (TypeError $e) {
// Handle type-related errors specifically
error_log("Type error occurred: " . $e->getMessage());
// Return graceful response to user
http_response_code(400);
echo json_encode(['error' => 'Invalid input data']);
} catch (Exception $e) {
// Handle general exceptions
error_log("General error: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Internal server error']);
}Implementing Custom Error Handlers
Creating custom error handlers allows you to centralize error management and provide consistent responses across your application. PHP's set_error_handler() and set_exception_handler() functions are essential tools for this approach.
class ErrorHandler {
public static function handlePhpError($errno, $errstr, $errfile, $errline) {
// Log the error
error_log("PHP Error [$errno]: $errstr in $errfile on line $errline");
// Only show errors in development
if (defined('ENVIRONMENT') && ENVIRONMENT === 'development') {
echo "Error: $errstr in $errfile on line $errline\n";
}
// Prevent script termination for non-fatal errors
return true;
}
public static function handleException($exception) {
// Log the exception
error_log("Uncaught Exception: " . $exception->getMessage());
// Send appropriate HTTP response
http_response_code(500);
if (defined('ENVIRONMENT') && ENVIRONMENT === 'development') {
echo json_encode([
'error' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace()
]);
} else {
echo json_encode(['error' => 'An internal error occurred']);
}
}
}
// Register custom handlers
set_error_handler(['ErrorHandler', 'handlePhpError']);
set_exception_handler(['ErrorHandler', 'handleException']);Comprehensive Logging Strategy
Effective logging requires careful consideration of what to log, where to log it, and how to structure log entries. A well-designed logging system should provide sufficient information for debugging while maintaining performance.
class Logger {
private static $logFile = '/var/log/myapp.log';
public static function log($level, $message, $context = []) {
$timestamp = date('Y-m-d H:i:s');
$logEntry = sprintf(
"[%s] %s: %s %s\n",
$timestamp,
strtoupper($level),
$message,
json_encode($context)
);
file_put_contents(self::$logFile, $logEntry, FILE_APPEND | LOCK_EX);
}
public static function info($message, $context = []) {
self::log('info', $message, $context);
}
public static function error($message, $context = []) {
self::log('error', $message, $context);
}
public static function debug($message, $context = []) {
self::log('debug', $message, $context);
}
}
// Usage example
try {
$user = User::find($_GET['id']);
Logger::info('User retrieved successfully', ['user_id' => $user->id]);
} catch (Exception $e) {
Logger::error('Failed to retrieve user', [
'user_id' => $_GET['id'],
'error' => $e->getMessage()
]);
throw $e;
}Error Handling in API Development
API error responses require special attention to maintain consistency and provide clear feedback to consumers. Proper HTTP status codes and structured error responses are crucial for API reliability.
class ApiErrorHandler {
public static function handleApiError($exception, $statusCode = 500) {
// Log the error
error_log("API Error: " . $exception->getMessage());
// Return JSON response
http_response_code($statusCode);
header('Content-Type: application/json');
echo json_encode([
'error' => [
'code' => $statusCode,
'message' => self::getErrorMessage($statusCode),
'timestamp' => time()
]
]);
}
private static function getErrorMessage($code) {
$messages = [
400 => 'Bad Request',
401 => 'Unauthorized',
403 => 'Forbidden',
404 => 'Not Found',
500 => 'Internal Server Error'
];
return $messages[$code] ?? 'Unknown Error';
}
}
// Usage in API endpoints
try {
$data = json_decode(file_get_contents('php://input'), true);
$validatedData = validateUserData($data);
$user = createUser($validatedData);
http_response_code(201);
echo json_encode(['user' => $user]);
} catch (ValidationException $e) {
ApiErrorHandler::handleApiError($e, 400);
} catch (NotFoundException $e) {
ApiErrorHandler::handleApiError($e, 404);
} catch (Exception $e) {
ApiErrorHandler::handleApiError($e, 500);
}Comparison of Error Handling Approaches
| Approach | Pros | Cons | Best Use Case |
|---|---|---|---|
| Try-Catch | Simple, direct control | Can clutter code | Small-scale applications |
| Custom Error Handlers | Centralized management | Requires setup | Large applications |
| Logging Frameworks | Advanced features | Overhead | Enterprise applications |
| API-Specific Handlers | Consistent responses | Limited to APIs | RESTful services |
Performance Considerations in Error Handling
While comprehensive error handling is crucial, it's important to balance functionality with performance. Excessive logging or complex error processing can impact application performance.
class OptimizedErrorHandler {
private static $logLevel = 'error'; // Configurable level
public static function log($level, $message, $context = []) {
// Only log at configured level or higher
$levels = ['debug' => 0, 'info' => 1, 'warning' => 2, 'error' => 3];
if ($levels[$level] >= $levels[self::$logLevel]) {
// Use buffered logging for performance
static $buffer = [];
$buffer[] = self::formatLogEntry($level, $message, $context);
// Flush buffer periodically
if (count($buffer) >= 10) {
self::flushBuffer($buffer);
$buffer = [];
}
}
}
private static function formatLogEntry($level, $message, $context) {
return sprintf(
"[%s] %s: %s %s\n",
date('Y-m-d H:i:s'),
strtoupper($level),
$message,
json_encode($context)
);
}
private static function flushBuffer($buffer) {
file_put_contents('/var/log/myapp.log', implode('', $buffer), FILE_APPEND | LOCK_EX);
}
}Error Handling Best Practices Summary
The following table summarizes key best practices for PHP error handling:
| Practice | Description | Benefits |
|---|---|---|
| Use Specific Exception Types | Catch specific exceptions rather than generic ones | Better error handling and debugging |
| Implement Centralized Logging | Use consistent logging across the application | Easier debugging and monitoring |
| Provide User-Friendly Messages | Hide technical details from end users | Improved user experience |
| Log Context Information | Include relevant data with error logs | Faster issue resolution |
| Handle Errors at Appropriate Levels | Different error types require different responses | Proper application flow |
| Monitor Error Rates | Track error frequencies and patterns | Proactive system maintenance |
