Lessons → PHP Error Handling

PHP Error Handling

PHP
⏱ 20 min read📖 IntermediateNot completed

Error handling is essential for building robust PHP applications. PHP provides several mechanisms — from basic error reporting to try/catch exceptions — to handle things that go wrong gracefully.

Types of Errors in PHP

TypeDescriptionFatal?
NoticeMinor issue (undefined variable)No
WarningSomething wrong but continuesNo
Fatal ErrorStops execution immediatelyYes
Parse ErrorSyntax error in codeYes
ExceptionThrown manually, catchableNo (if caught)

Basic Error Reporting

PHP
<?php
// Show ALL errors (development only!)
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Hide errors (production)
error_reporting(0);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php_errors.log');
?>

try / catch / finally

PHP
<?php
try {
    // Code that might fail
    $result = 10 / 0;
    throw new Exception("Something went wrong!");

} catch (Exception $e) {
    // Handle the error
    echo "Error: " . $e->getMessage();
    echo "File: "  . $e->getFile();
    echo "Line: "  . $e->getLine();

} finally {
    // Always runs — whether error or not
    echo "This always runs!";
}
?>

Multiple catch blocks

PHP
<?php
function connectDB(string $host): PDO {
    try {
        return new PDO("mysql:host=$host;dbname=test", 'user', 'pass');
    } catch (PDOException $e) {
        throw new RuntimeException("DB connection failed: " . $e->getMessage());
    }
}

try {
    $pdo = connectDB('localhost');
    $stmt = $pdo->query("SELECT * FROM users");

} catch (PDOException $e) {
    echo "Database error: " . $e->getMessage();

} catch (RuntimeException $e) {
    echo "Runtime error: " . $e->getMessage();

} catch (Exception $e) {
    // Catch anything else
    echo "General error: " . $e->getMessage();

} finally {
    echo "Cleanup code here";
}
?>

Custom Exception Classes

PHP
<?php
// Define custom exceptions
class ValidationException extends Exception {
    private array $errors;

    public function __construct(array $errors) {
        $this->errors = $errors;
        parent::__construct("Validation failed");
    }

    public function getErrors(): array {
        return $this->errors;
    }
}

class NotFoundException extends Exception {
    public function __construct(string $resource, int $id) {
        parent::__construct("$resource with ID $id not found", 404);
    }
}

// Using custom exceptions
function findUser(int $id): array {
    $user = getUserFromDB($id);
    if (!$user) {
        throw new NotFoundException('User', $id);
    }
    return $user;
}

function createUser(array $data): void {
    $errors = [];
    if (empty($data['name']))  $errors[] = 'Name is required';
    if (empty($data['email'])) $errors[] = 'Email is required';
    if (!empty($errors)) {
        throw new ValidationException($errors);
    }
    // save user...
}

try {
    createUser(['name' => '']);
} catch (ValidationException $e) {
    foreach ($e->getErrors() as $error) {
        echo "• $error
";
    }
} catch (NotFoundException $e) {
    echo $e->getMessage(); // User with ID 5 not found
    http_response_code($e->getCode()); // 404
}
?>

Global Exception Handler

PHP
<?php
// Catch ALL unhandled exceptions
set_exception_handler(function (Throwable $e) {
    error_log($e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine());

    // Show friendly error page instead of crash
    http_response_code(500);
    echo "<h1>Something went wrong</h1>";
    echo "<p>We're working on it. Please try again later.</p>";
});

// Catch ALL errors (PHP 7+)
set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});
?>

Real-World Example — File Upload

PHP
<?php
function uploadFile(array $file, string $destination): string {
    // Validate file exists
    if ($file['error'] !== UPLOAD_ERR_OK) {
        throw new RuntimeException("Upload failed with error code: " . $file['error']);
    }

    // Validate file type
    $allowed = ['image/jpeg', 'image/png', 'image/gif'];
    if (!in_array($file['type'], $allowed)) {
        throw new InvalidArgumentException("Invalid file type: " . $file['type']);
    }

    // Validate file size (max 2MB)
    if ($file['size'] > 2 * 1024 * 1024) {
        throw new OverflowException("File too large: " . $file['size'] . " bytes");
    }

    // Move file
    $filename = uniqid() . '_' . basename($file['name']);
    $path = $destination . '/' . $filename;

    if (!move_uploaded_file($file['tmp_name'], $path)) {
        throw new RuntimeException("Failed to move uploaded file");
    }

    return $filename;
}

try {
    $filename = uploadFile($_FILES['photo'], '/uploads');
    echo "Uploaded: $filename";

} catch (InvalidArgumentException $e) {
    echo "Invalid file: " . $e->getMessage();
} catch (OverflowException $e) {
    echo "File too large: " . $e->getMessage();
} catch (RuntimeException $e) {
    echo "Upload error: " . $e->getMessage();
}
?>
💡
Never show raw errors in production! Always log errors server-side and show a friendly message to users. Raw PHP errors expose your code structure to attackers.
💡
In Laravel, exceptions are handled automatically! The app/Exceptions/Handler.php file catches all exceptions and returns appropriate responses. You rarely need manual try/catch in controllers.
← All Lessons Next Lesson →
🧠

Test your knowledge!

Take a quiz to reinforce what you learned.

Take Quiz →