Kategoriler
PHP

PHP’de İstisnalar ve Hata Yönetimi

PHP betiklerinde sunucu, algoritma ya da kullanıcı kaynaklı anlık veya kalıcı olarak oluşan sorunlara istisna deniyor. Veri tabanı sunucusunun beklenilen cevabı vermiyor olması istisnaya en genel örnektir.

PHP bir betikte sözdizimi ya da farklı bir kod kaynaklı sorun meydana geliyorsa buna hata denir. Varsayılan olarak PHP bu hataları basit bir ileti ile ekrana yazdırır ancak bu projenin yayın aşamasında tercih ve tavsiye edilen bir şey değildir.

Geliştirme sürecindeki ya da yayında ki bir projede istisna ve hataların ekrana güvenilir ve geliştiricinin sorunu anlayabileceği şekilde gösterilmesi tercih edilir.

İstisnalar ve Kullanımları

PHP diğer programlama dillerindekini benzer bir istisna modeline sahiptir. Bir istisna oluşturabilir (throw) ve yakalanabilir (catch). Olası istisnaların yakalanabilmesi için, kod bir try bloğu içine alınabilir. Her try bloğuna karşılık en az bir tane catch ve ya finally bloğu olması gerekir.

Bir istisna oluşturulursa ve geçerli kapsam bağlamında catch bloğu yoksa, istisna, eşleşen bir catch bloğu bulana kadar çağrı yığıtını çağıran işleve “kabarcıklandırır”.
Yol boyunca karşılaşılan tüm finally blokları çalıştırılır. Eğer çağrı yığıtı, eşleşen bir catch bloğu bulamadan küresel bağlama kadar boşalırsa ve bir küresel istisna işleyici de atananmamışsa, ölümcül hata vererek sonlanır.

Oluşturulan nesne ya bir Exception sınıfı ya da Exception alt sınıfının örneği olmalıdır. Bunu sağlayan bir nesne oluşturmaya çalışmak throw ölümcül bir PHP hatasına yol açmaz.

catch

Bir catch bloğu oluşturulan bir istisnaya nasıl yanıt verileceğini tanımlar. Bir catch bloğu işleyebileceği bir veya daha fazla istisna veya hata türünü ve isteğe bağlı olarak istisnanın atanacağı değişkeni tanımlar. İlk catch bloğu, nesneyi işleyecek throw nesnesinin türüyle eşleşen bir hata veya istisnayla karşılaştığında bunları engelleyecektir.

finally

catch bloklarının yerine veya sonrasında bir finally bloğu da belirtilebilir. Bir istisna oluşmamışsa bile ve normal çalışmaya dönmeden önce finally bloğu içindeki kodlar daima try ve catch bloklarından sonra çalıştırırlır.

function inverse($x)
{
    if($x == 0){
        throw new Exception("Sıfıra bölme.");
    }else{
        return 1/$x;
    }
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'İstisna yakalandı : ' . $e->getMessage() . "\n";
}

Yukarıdaki kodları satır satır okumak gerekirse; inverse isimli bir fonksiyon oluşturulmuş, bu fonksiyon $x isimli bir parametre alıyor. $x parametresi 0 ise bir istisna fırlatıyor değilse 1’i $x parametresine bölüp döndürüyor.
Bir istisna fırlatılırsa bunu yakalamak için try bloğu içerisinde; önce parametre olarak 5 gönderiliyor. Ekrana 0.2 yazıyor. Sonraki satırda parametre olarak 0 gönderiliyor ve bir istisna fırlatıldığı için catch bloğu çalışıyor.
Bu örneğin çıktısı şu şekilde olacaktır;

0.2
İstisna yakalandı : Sıfıra bölme.

finally bloğu bulunan bir örnekte yapalım.

function inverse($x)
{
    if(!$x){
        throw new Exception("Sıfıra bölme.");
    }else{
        return 1/$x;
    }
}

try {
    echo inverse(5) . "\n";
} catch (Exception $e) {
    echo 'İstisna yakalandı : ' . $e->getMessage() . "\n";
}finally{
    echo "Birinci finally bloğu. \n";
}

try {
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'İstisna yakalandı : ' . $e->getMessage() . "\n";
}finally{
    echo "İkinci finally bloğu. \n";
}

Yukarıdaki örneğin çıktısı;

0.2
Birinci finally bloğu. 
İstisna yakalandı : Sıfıra bölme.
İkinci finally bloğu. 

Gördüğünüz gibi finally bloğu bir istisna yakalansın, yakalanmasın her durumda çalıştırılıyor.

Verdiğim örneklerde istisna fırlatma işlemi (throw) başka bir fonksiyon içerisinde gerçekleştirdim ancak doğrudan try bloğu içerisinde de yapılabilirdi.

$bolunen = 20;
$bolen = 0;

try {
    if($bolen == 0){
        throw new Exception("Sıfıra bölme işlemi yapılamaz.");
    }
    echo "Sonuç : " . $bolunen / $bolen;
} catch (Exception $e) {
    echo 'İstisna yakalandı : ' . $e->getMessage() . "\n";
}

Yukarıdaki örneğin çıktısı;

İstisna yakalandı : Sıfıra bölme işlemi yapılamaz.

Bir istisna yakalama (try) bloğu içerisinde bir istisna fırlatıldıktan (throw) sonraki kodlar çalışmayacaktır.

Hata Raporlama İşlemleri

Bir betik içerisinde kodlardan kaynaklanan bir sorun oluştuğunda, oluşan soruna hata denilir. PHP varsayılan olarak oluşan hataları küçük bir bilgi mesajı ile birlikte ekrana ve bir günlük kayıt (log) dosyası içerisine yazdırır. Böylece oluşan hatalar anlık ya da daha sonra programcı tarafından görülüp giderilmesi sağlanır.

PHP’de hataların seviyeleri bulunur. Bu seviyeler hatanın türünü ve ciddiyetini ifade eder.

DeğerSabitAçıklamaÖrnek
1E_ERRORÖlümcül çalışma zamanı hatalarıdır. Yürütme/çalıştırma durdurulur.Olmayan bir fonksiyonun çağırılmaya çalışılması.
2E_WARNINGÖlümcül olmayan çalışma zamanı hatalarıdır. Yürütme/çalıştırma durdurulmaz.PHP’nin ön tanımlı bir fonksiyonunun hatalı kullanımı
4E_PARSEÇalışma zamanı çözümleme hatalarıdır. Çözümleme hatalarını sadece çözümleyici üretir.En yaygın olanı noktalı virgülün unutulmasıdır. 🙂
8E_NOTICEÇalışma zamanı bildirimleridir. Betikte bir hataya sebep olabilecek bir şeylerin saptandığını bildirir.Olmayan bir değişkenin kullanılmaya çalışılması.
2048E_STRICTPHP kodunun ileriye dönük uyumluluğunu göz önünde bulundurarak PHP tarafından yapılan önerileri etkin kılar.
32767E_ALLTüm hatalar, uyarılar ve bildirimler.

PHP’de yukarıdaki tabloda bulunmayan farklı hata seviyeleri de bulunur ancak onlar daha çok PHP’nin kendisi ile ilgili hatalar içindir.

PHP’de hata raporlama sürecini yönetmek için iki farklı yol seyredilebilir.

Bunlardan ilki PHP’nin çalışacağı sunucudaki php.ini dosyasındaki error_reporting yapılandırmasına müdahale etmektir ki buradaki en büyük sorun, kodları çalıştıracağınız her sunucuda bu yapılandırmayı yapmanız gerekir ve bazı sunucu barındırma hizmetleri php.ini yapılandırma dosyasına erişim izni vermez.

İkinci yol ise; PHP betiği içinde error_reporting() fonksiyonu ile bu yapılandırmayı çalışma zamanında yapmaktır.

error_reporting() fonksiyonu parametre olarak gösterilmesi istenen hata seviyelerini aralarında dik çizgi (|) olacak şekilde alır.

error_reporting(E_ERROR | E_WARNING);

Yukarıdaki kullanım E_ERROR ve E_WARNING seviyesindeki hataları raporla anlamına gelir.

Bir hata seviyesinin raporlanmamasını istiyorsanız başına ~ işareti koyarak belirtebilirsiniz.

error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);

Yukarıdaki kullanım tüm E_NOTICE ve E_STRICT hata seviyeleri hariç tüm hataları raporla anlamına gelir.

Not : (~) işaretini Türkçe Q klavyelerde ALTGR+ü tuş kombinasyonunun ardından birkez boşluk tuşuna basarak yapabilirsiniz.

Ya da aynı işlemi (^) işareti ile de yapabilirsiniz. Bu işaret kendisinden sonra gelen hata seviyesinin raporlanmaması gerektiğini bildirir.

error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT);

Bu kullanım şekli de E_NOTICE ve E_STRICT seviyeleri hariç tüm hataları raporla anlamına gelir.

Tüm hata raporlamalarını kapatmak için;

error_reporting(0);

şeklinde tanımlanır.

Hata Denetim Operatörü

Ölümcül olmayan hataların bir hata üretmesini durdurmak için kullanılır. @ işareti PHP’de hata denetim operatörü olarak kullanılmaktadır.

Bir hata oluşturması muhtemel olan satırın başına @ operatörü konularak o hatanın yok sayılması sağlanır.

Önemli : En başta da belirttiğim gibi oluşacak hatanın ölümcül ya da kritik olmaması gerekir.

<?php
echo @$tanimsizDegisken;
?>

$tanimsizDegisken isimli bir değişken daha önce tanımlı olmadığı için normal şartlarda E_NOTICE seviyesinde bir hata döndürmesi gerekir ancak başına @ operatörü geldiği için bu hata es geçilecektir.

Yazar Muhammet ŞAFAK

1992 İstanbul doğumluyum. 2008 yılından beri profesyonel olarak PHP geliştiriyorum. Her ne kadar ağırlıklı olarak PHP üzerinde çalışsam da C, C++, Python, Java programlama dillerini de kullanıyorum.

Bir Cevap Yazın