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

ApproachProsConsBest Use Case
Try-CatchSimple, direct controlCan clutter codeSmall-scale applications
Custom Error HandlersCentralized managementRequires setupLarge applications
Logging FrameworksAdvanced featuresOverheadEnterprise applications
API-Specific HandlersConsistent responsesLimited to APIsRESTful 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:

PracticeDescriptionBenefits
Use Specific Exception TypesCatch specific exceptions rather than generic onesBetter error handling and debugging
Implement Centralized LoggingUse consistent logging across the applicationEasier debugging and monitoring
Provide User-Friendly MessagesHide technical details from end usersImproved user experience
Log Context InformationInclude relevant data with error logsFaster issue resolution
Handle Errors at Appropriate LevelsDifferent error types require different responsesProper application flow
Monitor Error RatesTrack error frequencies and patternsProactive system maintenance

Learn more with useful resources