PHP Exception Handling

Mastering Errors & Exceptions in PHP

Oleh: Ahmad Muyassar, S.Kom.,M.Cs

Agenda Pembelajaran

01. Errors vs Exceptions
02. Try, Catch, Finally
03. Throwing Exceptions
04. Custom Exceptions
05. Best Practices
01

Errors vs Exceptions

Memahami Dasar Masalah

Apa itu Error?

Error adalah masalah serius yang biasanya terjadi di tingkat sistem atau lingkungan runtime PHP.

Apa itu Exception?

Exception adalah kondisi abnormal yang terjadi saat kode dieksekusi (Runtime).

Perbedaan Utama

Fitur Error Exception
Sumber Environment/System Application Logic
Handling Sulit/Fatal Bisa di-catch
Impact Stop Script (Fatal) Flow Control

PHP 7+ Throwable

Sejak PHP 7, Error dan Exception mengimplementasikan interface yang sama: Throwable.


interface Throwable {
    public function getMessage();
    public function getCode();
    public function getFile();
    public function getLine();
    public function getTrace();
    // ...
}
            

Hierarki Throwable

  • Throwable
    • Error (System issues)
      • ArithmeticError
      • ParseError
      • TypeError
    • Exception (User issues)
      • LogicException
      • RuntimeException

Traditional Error Handling

Sebelum Exception populer, kita sering menggunakan if-else atau die().


$file = fopen("data.txt", "r");
if (!$file) {
    die("Gagal membuka file!");
}
// Lanjut proses...
            

Masalah: Kode logika bercampur dengan error handling.

Mengapa Exception Lebih Baik?

02

Try, Catch, Finally

Mekanisme Penanganan

Blok Try-Catch

Bungkus kode yang berpotensi error di dalam blok try.


try {
    // Kode yang mungkin melempar Exception
    $data = getDataFromApi();
} catch (Exception $e) {
    // Kode ini jalan jika terjadi Exception
    echo "Terjadi kesalahan: " . $e->getMessage();
}
            

Object Exception

Variabel $e di blok catch adalah object dari class Exception.


try {
    // ...
} catch (Exception $e) {
    echo $e->getMessage(); // Pesan error
    echo $e->getCode();    // Kode error
    echo $e->getFile();    // File penyebab
    echo $e->getLine();    // Baris error
}
            

Multiple Catch Blocks

Kita bisa menangkap jenis Exception yang berbeda secara spesifik.


try {
    // ...
} catch (DatabaseException $e) {
    echo "Masalah Database";
} catch (NetworkException $e) {
    echo "Masalah Koneksi";
} catch (Exception $e) {
    echo "Masalah Umum Lainnya";
}
            

Urutan Catch

PENTING: Tangkap Exception dari yang paling SPESIFIK ke yang paling UMUM.

Jika Exception (parent) ditaruh di atas, child exception tidak akan pernah tertangkap.

Catching Multiple Exceptions (PHP 7.1+)

Gunakan pipa | untuk menangkap beberapa tipe sekaligus.


try {
    // ...
} catch (MissingFileException | PermissionException $e) {
    logError($e->getMessage());
    echo "Gagal akses file.";
}
            

Blok Finally

Blok finally akan SELALU dieksekusi, baik terjadi exception maupun tidak.

Cocok untuk cleanup resource (tutup koneksi DB, tutup file).

Contoh Finally


$fh = fopen("test.txt", "w");
try {
    fwrite($fh, "Data");
    // Simulasi error
    throw new Exception("Oops");
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
} finally {
    echo "Menutup file...";
    fclose($fh); // Pasti dijalankan
}
            

Flow Eksekusi (Tanpa Error)

  1. Masuk blok try.
  2. Semua kode di try sukses.
  3. Blok catch DILEWATI.
  4. Masuk blok finally.
  5. Lanjut ke kode setelah try-catch-finally.

Flow Eksekusi (Dengan Error)

  1. Masuk blok try.
  2. Error terjadi di baris X.
  3. Sisa kode di try STOP.
  4. Masuk blok catch yang cocok.
  5. Masuk blok finally.
  6. Lanjut ke kode setelahnya (kecuali di-stop di catch).
03

Throwing Exceptions

Melempar Masalah

Keyword throw

Gunakan keyword throw untuk memicu Exception secara manual.


function bagi($a, $b) {
    if ($b == 0) {
        throw new Exception("Tidak bisa bagi dengan nol!");
    }
    return $a / $b;
}
            

Kapan harus throw?

Built-in Exceptions

PHP menyediakan banyak class Exception bawaan (SPL).

Contoh InvalidArgumentException


function setAge($age) {
    if ($age < 0) {
        throw new InvalidArgumentException("Umur harus positif");
    }
    $this->age = $age;
}
            

Re-throwing Exceptions

Kita bisa menangkap exception, melakukan sesuatu (misal logging), lalu melemparnya kembali.


try {
    doSomething();
} catch (Exception $e) {
    logger($e->getMessage()); // Log dulu
    throw $e; // Lempar lagi ke atas
}
            

Exception Bubbling

Jika Exception tidak ditangkap di fungsi saat ini, dia akan "naik" ke fungsi pemanggil (Caller), terus sampai ke Global Scope.

Func C (Throw) -> Func B -> Func A (Catch)

Uncaught Exceptions

Jika Exception sampai ke Global Scope dan tidak ada yang menangkap, PHP akan menampilkan Fatal Error: Uncaught Exception.

Ini buruk untuk User Experience.

Global Exception Handler

Gunakan set_exception_handler untuk menangkap semua exception yang lolos.


set_exception_handler(function ($e) {
    echo "Maaf, terjadi kesalahan sistem.";
    // Log error ke file
});
            

Throw sebagai Expression (PHP 8.0)

Sekarang throw bisa digunakan di tempat yang hanya menerima expression.


$value = $input['user'] ?? throw new Exception("User wajib ada");

$result = $condition ? 'Valid' : throw new InvalidArgumentException();
            
04

Custom Exceptions

Membuat Exception Sendiri

Mengapa Custom Exception?

Cara Membuat Custom Exception

Cukup buat class baru yang extends Exception.


class SaldoTidakCukupException extends Exception {
    // Bisa kosong, mewarisi semua fitur parent
}
            

Menggunakan Custom Exception


function tarikTunai($jumlah, $saldo) {
    if ($jumlah > $saldo) {
        throw new SaldoTidakCukupException("Saldo kurang!");
    }
    return $saldo - $jumlah;
}
            

Catching Custom Exception


try {
    tarikTunai(100000, 5000);
} catch (SaldoTidakCukupException $e) {
    echo "Transaksi Gagal: " . $e->getMessage();
    // Tampilkan saran topup
} catch (Exception $e) {
    echo "Error Sistem Lainnya";
}
            

Menambah Method Custom


class ValidationException extends Exception {
    private $errors = [];

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

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

Contoh Penggunaan Method Custom


try {
    validateInput($_POST);
} catch (ValidationException $e) {
    $fieldErrors = $e->getErrors();
    print_r($fieldErrors); // Tampilkan detail error per field
}
            

Domain Exceptions

Kelompokkan Exception berdasarkan domain bisnis aplikasi Anda.

Abstract Exception / Interface

Anda bisa membuat Interface untuk menandai Exception tertentu.


interface PublicExceptionInterface {}

class UserMessageException extends Exception implements PublicExceptionInterface {}

// Di Global Handler:
if ($e instanceof PublicExceptionInterface) {
    echo $e->getMessage(); // Aman ditampilkan ke user
}
            

Tips Penamaan

Selalu akhiri nama class dengan kata Exception.

Good: UserNotFoundException

Bad: UserNotFound, UserError

05

Best Practices

Tips & Trik Profesional

Jangan Gunakan untuk Flow Control

Exception itu "mahal" (berat secara performa). Jangan gunakan untuk logika biasa.


// BAD
try {
    $user = findUser();
} catch (NotFoundException $e) {
    createUser();
}

// GOOD
$user = findUser();
if (!$user) {
    createUser();
}
            

Exception Wrapping

Bungkus Low-Level Exception menjadi High-Level Exception agar lebih bermakna.


try {
    $db->connect();
} catch (PDOException $e) {
    // Sembunyikan detail SQL, lempar error aplikasi
    throw new DatabaseConnectionException("Gagal koneksi DB", 0, $e);
}
            

Parameter $previous

Parameter ke-3 di constructor Exception adalah $previous. Gunakan untuk menyimpan rantai exception (seperti contoh wrapping di atas).

Ini membantu debugging untuk melacak akar masalah.

Logging

Selalu log exception yang tidak terduga (500 Internal Server Error).

Jangan log exception yang memang diharapkan (404 Not Found, 422 Validation Error), kecuali untuk audit trail.

Security: Stack Traces

JANGAN PERNAH menampilkan Stack Trace ke User di Production!

Stack trace berisi path file, nama database, password, dll. Tampilkan pesan generik "Terjadi Kesalahan" ke user, tapi log detailnya di server.

Modern PHP: Match Expression

Kita bisa menggunakan match untuk handling error code.


try {
    // ...
} catch (ApiException $e) {
    $message = match ($e->getCode()) {
        404 => 'Data tidak ditemukan',
        500 => 'Server sedang sibuk',
        default => 'Error tidak diketahui',
    };
    echo $message;
}
            

Kesimpulan: Try-Catch

Kesimpulan: Throwing

Referensi Belajar

Terima Kasih

Happy Coding!

1 / 51