Anda seharusnya tidak menangkap pengecualian kecuali Anda bermaksud melakukan sesuatu yang berarti .
"Sesuatu yang bermakna" mungkin salah satunya:
Menangani pengecualian
Tindakan bermakna yang paling jelas adalah menangani pengecualian, misalnya dengan menampilkan pesan kesalahan dan membatalkan operasi:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
Pembalakan atau pembersihan sebagian
Terkadang Anda tidak tahu bagaimana menangani dengan benar pengecualian dalam konteks tertentu; mungkin Anda kurang informasi tentang "gambaran besar", tetapi Anda ingin mencatat kegagalan sedekat mungkin dengan titik di mana hal itu terjadi. Dalam hal ini, Anda mungkin ingin menangkap, mencatat, dan melemparkan kembali:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
Skenario terkait adalah di mana Anda berada di tempat yang tepat untuk melakukan pembersihan untuk operasi yang gagal, tetapi tidak memutuskan bagaimana kegagalan harus ditangani di tingkat atas. Dalam versi PHP sebelumnya ini akan diimplementasikan sebagai
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
catch (Exception $e) {
$connect->disconnect(); // we don't want to keep the connection open anymore
throw $e; // but we also don't know how to respond to the failure
}
PHP 5.5 telah memperkenalkan finallykata kunci, jadi untuk skenario pembersihan sekarang ada cara lain untuk mendekati ini. Jika kode pembersihan perlu dijalankan tidak peduli apa yang terjadi (mis. Baik pada kesalahan maupun kesuksesan) sekarang mungkin untuk melakukan ini sementara secara transparan memungkinkan segala pengecualian yang dilemparkan untuk disebarkan:
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
Abstraksi kesalahan (dengan chaining pengecualian)
Kasus ketiga adalah di mana Anda ingin mengelompokkan banyak kegagalan yang mungkin secara logis di bawah payung yang lebih besar. Contoh untuk pengelompokan logis:
class ComponentInitException extends Exception {
// public constructors etc as in Exception
}
class Component {
public function __construct() {
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);
}
}
}
Dalam hal ini, Anda tidak ingin pengguna Componenttahu bahwa itu diimplementasikan menggunakan koneksi database (mungkin Anda ingin menjaga opsi Anda terbuka dan menggunakan penyimpanan berbasis file di masa depan). Jadi spesifikasi Anda untuk Componentakan mengatakan bahwa "dalam kasus kegagalan inisialisasi, ComponentInitExceptionakan dibuang". Hal ini memungkinkan konsumen Componentuntuk menangkap pengecualian dari tipe yang diharapkan sementara juga memungkinkan kode debug untuk mengakses semua detail (tergantung pada implementasi) .
Memberikan konteks yang lebih kaya (dengan chaining pengecualian)
Akhirnya, ada beberapa kasus di mana Anda mungkin ingin memberikan lebih banyak konteks untuk pengecualian. Dalam hal ini masuk akal untuk membungkus pengecualian di yang lain yang menampung lebih banyak informasi tentang apa yang Anda coba lakukan ketika kesalahan terjadi. Sebagai contoh:
class FileOperation {
public static function copyFiles() {
try {
$copier = new FileCopier(); // the constructor may throw
// this may throw if the files do no not exist
$copier->ensureSourceFilesExist();
// this may throw if the directory cannot be created
$copier->createTargetDirectory();
// this may throw if copying a file fails
$copier->performCopy();
}
catch (Exception $e) {
throw new Exception("Could not perform copy operation.", 0, $e);
}
}
}
Kasus ini mirip dengan yang di atas (dan contohnya mungkin bukan yang terbaik yang bisa muncul), tetapi menggambarkan titik memberikan lebih banyak konteks: jika pengecualian dilemparkan, ia memberi tahu kita bahwa salinan file gagal. Tetapi mengapa itu gagal? Informasi ini disediakan dalam pengecualian yang dibungkus (yang mungkin ada lebih dari satu tingkat jika contohnya jauh lebih rumit).
Nilai melakukan ini diilustrasikan jika Anda berpikir tentang skenario di mana misalnya membuat UserProfileobjek menyebabkan file akan disalin karena profil pengguna disimpan dalam file dan mendukung semantik transaksi: Anda dapat "membatalkan" perubahan karena hanya dilakukan pada Salin profil sampai Anda komit.
Dalam hal ini, jika Anda melakukannya
try {
$profile = UserProfile::getInstance();
}
dan akibatnya menangkap kesalahan pengecualian "Direktori target tidak dapat dibuat", Anda berhak untuk dibingungkan. Membungkus pengecualian "inti" ini di lapisan pengecualian lain yang menyediakan konteks akan membuat kesalahan lebih mudah untuk ditangani ("Membuat salinan profil gagal" -> "Operasi penyalinan file gagal" -> "Direktori target tidak dapat dibuat").