Tutorial PHP #25: Error Handling dan Exception di PHP

1. Jenis Error di PHP

PHP mengenal beberapa jenis error:

  • Parse Error - kesalahan sintaks, script tidak bisa dijalankan sama sekali
  • Fatal Error - error serius yang menghentikan script (misalnya function tidak ditemukan)
  • Warning - error yang tidak menghentikan script (misalnya file tidak ditemukan)
  • Notice - peringatan ringan (misalnya variabel belum didefinisikan)
  • Exception - error yang bisa "ditangkap" dan ditangani

2. try...catch

Gunakan try...catch untuk menangkap exception dan menanganinya dengan elegan.

<?php
function bagi(int $a, int $b): float {
    if ($b === 0) {
        throw new InvalidArgumentException("Tidak bisa membagi dengan nol!");
    }
    return $a / $b;
}

try {
    echo bagi(10, 2);    // Output: 5
    echo bagi(10, 0);    // Ini akan throw exception
    echo "Baris ini tidak akan dieksekusi";
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
    // Output: Error: Tidak bisa membagi dengan nol!
}
?>

3. Multiple catch

<?php
function prosesData(mixed $input): string {
    if (!is_array($input)) {
        throw new TypeError("Input harus berupa array");
    }
    if (empty($input)) {
        throw new RuntimeException("Array tidak boleh kosong");
    }
    return "Data valid: " . count($input) . " item";
}

try {
    echo prosesData("bukan array");
} catch (TypeError $e) {
    echo "Type Error: " . $e->getMessage();
} catch (RuntimeException $e) {
    echo "Runtime Error: " . $e->getMessage();
} catch (Exception $e) {
    // Tangkap semua exception lainnya
    echo "Error umum: " . $e->getMessage();
}
?>

4. finally

Blok finally selalu dieksekusi, tidak peduli apakah ada exception atau tidak. Berguna untuk cleanup seperti menutup file atau koneksi database.

<?php
function bacaFile(string $path): string {
    $file = fopen($path, "r");

    try {
        if (!$file) {
            throw new RuntimeException("File tidak bisa dibuka: $path");
        }
        $isi = fread($file, filesize($path));
        return $isi;
    } catch (RuntimeException $e) {
        echo "Error: " . $e->getMessage();
        return "";
    } finally {
        // Selalu tutup file - baik berhasil maupun error
        if ($file) fclose($file);
        echo "<br>File handle ditutup";
    }
}
?>

5. Custom Exception

<?php
class ValidationException extends RuntimeException {
    private array $errors;

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

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

class DatabaseException extends RuntimeException {
    public function __construct(string $query, Throwable $previous = null) {
        parent::__construct("Query gagal: $query", 0, $previous);
    }
}

// Penggunaan
function simpanUser(array $data): void {
    $errors = [];
    if (empty($data["nama"]))  $errors[] = "Nama wajib diisi";
    if (empty($data["email"])) $errors[] = "Email wajib diisi";

    if (!empty($errors)) {
        throw new ValidationException($errors);
    }
    // Proses simpan...
}

try {
    simpanUser(["nama" => ""]);
} catch (ValidationException $e) {
    echo $e->getMessage() . "<br>";
    foreach ($e->getErrors() as $err) {
        echo "- $err <br>";
    }
}
?>

6. Set Error Handler Global

<?php
// Tangkap semua uncaught exception
set_exception_handler(function (Throwable $e) {
    // Log error ke file
    error_log($e->getMessage() . " di " . $e->getFile() . ":" . $e->getLine());
    
    // Tampilkan pesan ramah ke user
    http_response_code(500);
    echo "Terjadi kesalahan pada server. Silakan coba lagi.";
});
?>

7. Ringkasan

  • throw untuk melempar exception, try...catch untuk menangkapnya
  • Gunakan multiple catch untuk menangani jenis exception berbeda
  • finally selalu dieksekusi - gunakan untuk cleanup resource
  • Buat custom exception class untuk error yang spesifik di aplikasi kamu

Tutorial berikutnya membahas koneksi database MySQL dengan MySQLi.