← Tilbage til koncepter

Error & Exception Handling

Try-catch blocks, custom exceptions, error handlers og Throwable hierarchy i moderne PHP

Kategori: Fundamentals

🎯 Key Points

  • try-catch-finally - Struktureret exception handling med cleanup i finally block
  • Throwable interface - Root interface for både Exception og Error classes (PHP 7+)
  • Exception hierarchy - Custom exceptions der extender base Exception class
  • Error class - Catchable errors som TypeError, DivisionByZeroError (PHP 7+)
  • Custom exceptions - Domain-specific exception classes med custom properties og methods
  • set_exception_handler() - Global exception handler for uncaught exceptions
  • set_error_handler() - Convert PHP errors (warnings, notices) til exceptions
  • finally block - Kode der altid eksekveres uanset om exception blev kastet
  • throw keyword - Kast exceptions for at signalere error conditions
  • Multiple catch blocks - Catch forskellige exception types med forskellig handling
  • Exception chaining - Previous exception parameter for nested error context
  • SPL exceptions - Built-in exception types som InvalidArgumentException, RuntimeException

💻 Kode Eksempel

<?php

// Custom exception hierarchy
class DatabaseException extends Exception {}
class ConnectionException extends DatabaseException {}
class QueryException extends DatabaseException {
    public function __construct(
        string $message,
        private string $query,
        int $code = 0,
        ?Throwable $previous = null
    ) {
        parent::__construct($message, $code, $previous);
    }
    
    public function getQuery(): string {
        return $this->query;
    }
}

// Database class with proper error handling
class Database {
    private ?PDO $connection = null;
    
    public function connect(string $dsn): void {
        try {
            $this->connection = new PDO($dsn);
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            throw new ConnectionException(
                "Failed to connect to database: {$e->getMessage()}",
                (int)$e->getCode(),
                $e
            );
        }
    }
    
    public function query(string $sql): array {
        if (!$this->connection) {
            throw new ConnectionException('Not connected to database');
        }
        
        try {
            $stmt = $this->connection->query($sql);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            throw new QueryException(
                "Query failed: {$e->getMessage()}",
                $sql,
                (int)$e->getCode(),
                $e
            );
        }
    }
}

// Usage with multiple catch blocks
try {
    $db = new Database();
    $db->connect('sqlite::memory:');
    
    // This will fail - invalid SQL
    $results = $db->query('INVALID SQL');
    
} catch (ConnectionException $e) {
    echo "Connection error: {$e->getMessage()}\n";
    // Handle connection errors specifically
    
} catch (QueryException $e) {
    echo "Query error: {$e->getMessage()}\n";
    echo "Failed query: {$e->getQuery()}\n";
    
    // Check if there's a previous exception
    if ($prev = $e->getPrevious()) {
        echo "Caused by: {$prev->getMessage()}\n";
    }
    
} catch (DatabaseException $e) {
    echo "General database error: {$e->getMessage()}\n";
    
} finally {
    echo "Cleanup completed\n";
}

// Custom error handler to convert errors to exceptions
set_error_handler(function($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

try {
    // This warning will become an exception
    $result = 10 / 0; // Division by zero warning
} catch (ErrorException $e) {
    echo "Caught error as exception: {$e->getMessage()}\n";
}

restore_error_handler();

💼 Hvornår bruges det?

  • API error responses hvor exceptions mappes til HTTP status codes og JSON error payloads
  • Database operations hvor connection failures, query errors og transaction rollbacks håndteres
  • File operations hvor missing files, permission errors og disk full scenarios catches gracefully
  • External API calls hvor network timeouts, invalid responses og rate limits triggerer exceptions
  • Form validation hvor ValidationException samler alle validation errors til user feedback
  • Payment processing hvor PaymentException håndterer declined cards, insufficient funds og gateway errors

⭐ Best Practices

  • Create custom exception hierarchies for domain-specific errors - gør det lettere at catch specifikt
  • Always catch most specific exceptions first - rækkefølge matters i multiple catch blocks
  • Use finally blocks for cleanup operations (close files, connections) der skal ske uanset hvad
  • Log exceptions med context - message, stack trace, request data for debugging production issues
  • Never catch Throwable unless du re-throws - catching alt kan skjule critical errors
  • Include previous exception i custom exceptions for full error chain og debugging context
  • Throw exceptions for exceptional conditions only - ikke til normal control flow
  • Use SPL exceptions når muligt - InvalidArgumentException, RuntimeException etc frem for generic Exception

ℹ️ Quick Info

Kategori
Fundamentals
Sværhedsgrad
Mellem