Exception Handling

İstisnalar, özel bir hata meydana geldiğinde kodun normal akışını değiştirmek için kullanılır.

İstisna yönetimi, eğer özel bir hata (istisnai) durumu meydana geldiğinde kod yürütümünün normal akışını değiştirir. Bu duruma istisna denir.

Normalde bir istisna tetiklendiğinde olanlar:


  • Güncel kod durumu kaydedilir.

  • Kod yürütümü, önceden tanımlanmış (özel) bir istisna yöneticisi fonksiyonuna dönüşür.

  • Duruma bağlı olarak; yönetici, kaydedilen kod durumundan yürütüme devam edebilir, kod yürütümünü yok edebilir veya kodda farklı bir yerden koda devam edebilir.



Sizlere birkaç hata yönetimi metodu göstereceğim:


  • Basit istisna kullanımı

  • Özel bir istisna yöneticisi kurmak

  • Çoklu istisnalar

  • İstisnayı yeniden fırlatmak

  • En üst düzey istisna yöneticisi kurmak



Not: İstisnalar sadece hata koşullarında kullanılmalıdır ve kodda belirli başka bir noktaya geçilmek için kullanılmamalıdır.

Basit İstisna Kullanımı

Bir istisna fırlatıldığında onun arkasındaki kodlar yürütülmez ve PHP, catch bloğu eşleşmesi aramaya çalışır.

Eğer bir istisna yakalanmazsa, "Uncaught Exception" (Yakalanamayan İstisna) adında kritik bir hata çıkar.

Bir istisnayı yakalamadan fırlatmaya çalışalım:

Kod:
<?php
//istisnalı fonksiyon kurma
function checkNum($number) {
if($number>1) {
throw new Exception("Value must be 1 or below");
}
return true;
}

//istisnayı tetikleme
checkNum(2);
?>



Yukarıdaki kodun çıktısı şöyle bir şey olmalı:

Kod:
Fatal error: Uncaught exception 'Exception'
with message 'Value must be 1 or below' in C:\webfolder\test.php:6
Stack trace: #0 C:\webfolder\test.php(12):
checkNum(28) #1 {main} thrown in C:\webfolder\test.php on line 6



Dene, Fırlat ve Yakala

Yukarıdaki örnekteki gibi hatayı önlemek için istisnayı yönetebilmesi adına münasip bir kod kurulmalı.

Münasip bir istisna kodu şunları içermeli:


  1. Dene: İstisnayı kullanan bir fonksiyon, try bloğunda olmalı. Eğer ki istisna tetiklenmezse kod normalmiş gibi devam edecek. Fakat eğer istisna tetiklenirse, istisna fırlatılacak.

  2. Fırlatma: Bu da istisnayı nasıl tetikleyeceğindir. Her throw, en azından bir catch sahip olmalı.

  3. Yakala: Bir catch bloğu, bir istisnayı geri alır ve istisna bilgisi içeren bir nesne oluşturur.



Geçerli bir kodla bir istisnayı tetiklemeye çalışalım:

Kod:
<?php
//istisnalı fonksiyon kurma
function checkNum($number) {
if($number>1) {
throw new Exception("Value must be 1 or below");
}
return true;
}

//try bloğunda istisnayı tetikleme
try {
checkNum(2);
//Eğer istisna fırlatılmışsa, bu yazı gösterilmeyecek
echo 'If you see this, the number is 1 or below';
}

//istisnayı yakalama
catch(Exception $e) {
echo 'Message: ' .$e->getMessage();
}
?>



Yukarıdaki kodun çıktısı şöyle bir şey olmalı:

Kod:
Message: Value must be 1 or below


Örneğin açıklaması:

Yukarıdaki kod istisnayı fırlatır ve yakalar:


  1. checkNum() fonksiyonu kuruldu. Sayının 1'den büyük olup olmadığını kontrol eder. Eğer büyükse, istisna fırlatılır.

  2. checkNum() fonksiyonu try bloğunda çağrılır.

  3. İstisna, checkNum() fonksiyonu ile beraber fırlatılır.

  4. Catch bloğu istisnayı geri alır ve istisna bilgisi içeren bir nesne ($e) oluşturur.

  5. İstisnadan hata mesajı, istisna nesnesinden $e->getMessage() çağrılarak yansıtılır.



Yine de "her fırlatmanın bir yakalaması olmalı" kuralını aşmanın tek yolu, kaydırıp giderek hataları halletmek için en üst düzey istisna yöneticisi kurmaktır.

Özel Bir İstisna Yöneticisi Kurmak

Özel bir istisna yöneticisi kurmak için PHP'de bir istisna meydana geldiğinde çağrılabilen fonksiyonlu ona has bir class kurmalı.

Bu özel istisna class'ı, PHP'nin istisna class'ından özellikleri devralır ve bunun yanısıra kendiniz de özel fonksiyonlar ekleyebilirsiniz.

Bir istisna class'ı kurmak gerekirse:

Kod:
<?php
class customException extends Exception {
public function errorMessage() {
//hata mesajı
$errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
.': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';
return $errorMsg;
}
}

$email = "[email protected]";

try {
//kontrol et eğer
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
//eğer e-posta geçerli değilse istisnayı fırlat
throw new customException($email);
}
}

catch (customException $e) {
//özel mesajı görüntüle
echo $e->errorMessage();
}
?>



Bu yeni class, eski istisna class'ının errorMessage() fonksiyonu ekli halidir. Eski class'ın kopyası olduğundan ve eski class'dan özellikleri ve metotları devraldığından istisna class'ını getLine(), getFile() ve getMessage() gibi kullanabiliriz.

Örneğin açıklaması:

Yukarıdaki kod istisnayı fırlatır ve özel istisna class'ı ile yakalar:


  1. Eski istisna class'ının uzantısı olarak customException() class'ı kuruldu. Bu yolla eski istisna class'ından tüm metotları ve özellikleri devralır.

  2. errorMessage() fonksiyonu kuruldu. Bu fonksiyon eğer e-posta adresi geçerli değilse hata mesajını alır.

  3. $email değişkeni uygun e-posta adresi olmayan string'e kurulur.

  4. Try bloğu çalıştırılır ve e-posta adresi geçersiz olduğundan bir istisna fırlatılır.

  5. Catch bloğu istisnayı yakalar ve hata mesajını görüntüler.



Çoklu İstisnalar

Kodda birçok durumu kontrol etmek için çoklu istisna kullanmak mümkündür.

Birçok if..else bloğu, bir switch veya yuvalanmış çoklu istisna kullanmak da mümkündür. Bu istisnalar farklı istisna class'ı kullanabilir ve farklı hata mesajları alabilir:

Kod:
<?php
class customException extends Exception {
public function errorMessage() {
//hata mesajı
$errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
.': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';
return $errorMsg;
}
}

$email = "[email protected]";

try {
//kontrol et eğer
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
//e-posta geçerli değilse istisnayı fırlat
throw new customException($email);
}
//e-posta adresinde "example"ı kontrol et
if(strpos($email, "example") !== FALSE) {
throw new Exception("$email is an example e-mail");
}
}

catch (customException $e) {
echo $e->errorMessage();
}

catch(Exception $e) {
echo $e->getMessage();
}
?>



Örneğin açıklaması:

Yukarıdaki kod iki durumu test eder ve durumlardan hiçbiri karşılaşmazsa istisnayı fırlatır:


  1. Eski istisna class'ının uzantısı olarak customException() class'ı kuruldu. Bu yolla eski istisna class'ından tüm metotları ve özellikleri devralır.

  2. errorMessage() fonksiyonu kuruldu. Bu fonksiyon eğer e-posta adresi geçerli değilse hata mesajını alır.

  3. $email değişkeni uygun e-posta adresi olmayan string kurulur lakin "example" string'ini içerir.

  4. Try bloğu yürütülür ve istisna ilk durumda fırlatılmaz.

  5. E-posta "example" string'ini içeriyorsa ikinci durum istisnayı tetikler.

  6. Catch bloğu istisnayı yakalar ve doğru hata mesajını görüntüler.



Eğer ki istisna customException class'ının olduğu yere fırlatılırsa ve orada hiç customException yakalaması yoksa sadece taban istisnası yakalar, istisna anca orada hallolur.

İstisnayı Yeniden Fırlatmak

Bazen, istisna fırlatıldığında, bunu standart yol harici farklı bir şekilde halletmek istersin. Bir istisnayı catch bloğu içinde ikinci kez fırlatmak mümkündür.

Kod dediğin kullanıcıdan sistem hatalarını saklar. Sistem hataları kodu yazan kişi için önemli olabilir lakin kullanıcının hiç umurunda olmaz. Kullanıcı için işleri kolaylaştırmak adına kullanıcı dostane mesajıyla istisnayı yeniden fırlatabilirsin.

Kod:
<?php
class customException extends Exception {
public function errorMessage() {
//hata mesajı
$errorMsg = $this->getMessage().' is not a valid E-Mail address.';
return $errorMsg;
}
}

$email = "[email protected]";

try {
try {
//"example"ın e-posta adresinde olup olmadığını kontrol et
if(strpos($email, "example") !== FALSE) {
//e-posta geçerli değilse istisnayı fırlat
throw new Exception($email);
}
}
catch(Exception $e) {
//istisnayı tekrar fırlat
throw new customException($email);
}
}

catch (customException $e) {
//özel mesajı görüntüle
echo $e->errorMessage();
}
?>



Yukarıdaki kod e-posta adresinin "example" string'ini içerip içermediğini test eder, eğer varsa istisna yeniden fırlatılır.


  1. Eski istisna class'ının uzantısı olarak customException() class'ı kuruldu. Bu yolla eski istisna class'ından tüm metotları ve özellikleri devralır.

  2. errorMessage() fonksiyonu kuruldu. Bu fonksiyon eğer e-posta adresi geçerli değilse hata mesajını alır.

  3. $email değişkeni uygun e-posta adresi olmayan string kurulur lakin "example" string'ini içerir.

  4. Try bloğu istisnayı yeniden fırlatmaya olanak sağlama amaçlı başka bir try bloğu içerir.

  5. E-posta, "example" string'ini içeriyorsa istisna tetiklenir.

  6. Catch bloğu istisnayı yakalar ve customException'ı yeniden fırlatır.

  7. customException yakalanır ve hata mesajını görüntüler.



Eğer ki istisna try bloğunda yakalanmazsa daha üst seviyelerde yakala bloğu arayacak.

En Üst Düzey İstisna Yöneticisi Kurmak

set_exception_handler() fonksiyonu, tüm yakalanmayan istisnaları halletmek için kullanıcı tanımlı fonksiyon kurar:

Kod:
<?php
function myException($exception) {
echo "<b>Exception:</b> " . $exception->getMessage();
}

set_exception_handler('myException');

throw new Exception('Uncaught Exception occurred');
?>



Yukarıdaki kodun çıktısı şöyle bir şey olmalı:

Kod:
Exception: Uncaught Exception occurred


Yukarıdaki kodda hiç catch bloğu yoktu. Bunun yerine en üst düzey istisna yöneticisi tetiklendi. Bu fonksiyon, yakalanmayan istisnaları yakalamak amaçlı kullanılmalı.

İstisna Kuralları


  • Potansiyel istisnaları yakalamaya yardımcı olmak amaçlı kod try bloğunda olabilir.

  • Her bir try bloğu veya throw, en az bir tane yakalama bloğuna eş bir şeye sahip olmalı.

  • Çoklu yakalama blokları, farklı istisna class'larını yakalamak için kullanılabilir.

  • İstisnalar, try bloğu içindeki catch bloğundan fırlatılabilir (veya yeniden fırlatılabilir).


aLinti..