7. İstisnalar ve hatalar
Bir sınıfın yöntemi düzeltilemez bir hatayla karşılaştığında (dosya yok, veritabanına bağlanılamadı, ağ bağlantısı kesik), konsolda (dosya, veritabanı) bir hata mesajı görüntülemez, bunun yerine bir istisna atar. Tüm istisnalar [\Exception] sınıfını genişletir. İstisnaların yanı sıra, PHP sınıfının iç işleyişi, temel sınıfı [\Error] olan hatalar da üretir. Her iki sınıf da PHP ve [\Throwable] arayüzlerini uygular.
7.1. Komut dosyası ağacı

7.2. [\Throwable] arayüzü
[\Throwable] arayüzü şu şekildedir:

Arayüzdeki yöntemlerin işlevleri şöyledir:

7.3. PHP 7'de önceden tanımlanmış istisnalar
PHP 7'de tanımlanan istisnalar, çeşitli istisna sınıflarını tanımlamaktadır:

- [1]'te, PHP'te önceden tanımlanmış istisnalar;
- [2]’te, PHP 7’nin SPL kütüphanesindeki (Standart PHP Kütüphanesi) istisnalar. SPL kütüphanesi, geliştiricilerin sıkça karşılaştığı sorunları çözmek amacıyla tasarlanmış sınıf ve arayüzlerden oluşan bir koleksiyondur.
7.4. PHP 7'de önceden tanımlanmış hatalar
PHP 7, çeşitli hata sınıflarını tanımlar:

[\Error] sınıfı, PHP'te önceden tanımlanmış tüm hataların üst sınıfıdır. [ErrorException] sınıfı, [\Error] sınıfının bir örneğini [\Exception] sınıfının bir örneği içinde kapsüllemeyi sağlar. Bu, yalnızca istisnaları işleyerek hata yönetimini standartlaştırmaya olanak tanır.
7.5. Örnek 1
İlk örnek olan [exceptions-01.php], hem PHP hatalarını hem de bir istisnayı göstermektedir:
<?php
// tüm hataların görüntülenmesi
ini_set("error_reporting", E_ALL);
ini_set("display_errors", "on");
// kod --------
$var=[];
// bilinmeyen anahtar
print $var["abcd"];
// sıfıra bölme
$var=7/0;
var_dump($var);
// sabit sınırlı dizi
$array = new \SplFixedArray(5);
$array[1] = 2;
$array[4] = "foo";
// sınırların dışında indeks
$array[5]=8;
Açıklamalar
- 4. satır: PHP'ten tüm hataları bildirmesi istenir. İkinci parametre, istenen hata seviyesidir:


- 5. satır: Hataların konsolda görüntülenmesi isteniyor;
- 9. satır: [$var] dizisinin var olmayan bir elemanına erişiliyor;
- 11. satır: sıfıra bölme işlemi yapılıyor;
- 14. satır: [SplFixedArray] sınıfının bir örneği oluşturuluyor. Bu sınıf, sabit sınırlı ve tamsayı indeksli bir dizi oluşturulmasına olanak tanır;
- 18. satır: dizide var olmayan bir elemana erişiliyor;
Sonuçlar
Yorumlar
- sonuçların 1. satırı: Bir dizinin mevcut olmayan bir anahtarına erişilmeye çalışılması, [E_NOTICE] seviyesinde bir PHP hatasına neden olur. Bu, komut dosyasının yürütülmesini kesintiye uğratmaz;
- sonuçların 3. satırı: Bir sayıyı sıfıra bölmek, [E_WARNING] seviyesinde bir PHP hatasına neden olur. Bu, komut dosyasının yürütülmesini kesintiye uğratmaz;
- sonuçların 6-9. satırları: [SplFixedArray] dizisinin mevcut olmayan bir indeksine erişim, [RuntimeException] türünde bir istisna oluşturur ve komut dosyasının çalışmasını durdurur;
7.6. İstisnaları Yönetme
[exceptions-02.php] komut dosyası, istisnaların nasıl yönetileceğini gösterir:
<?php
// tüm hatalar görüntülenir
ini_set("error_reporting", E_ALL);
ini_set("display_errors", "on");
// kod, try / catch ile çevrelenir
try {
$var = [];
// bilinmeyen anahtar
print $var["abcd"];
// sıfıra bölme
$var = 7 / 0;
var_dump($var);
// sabit sınırlı dizi
$array = new \SplFixedArray(5);
$array[1] = 2;
$array[4] = "foo";
// sınırların dışındaki indeks
$array[5] = 8;
// doğrulama
print "ce message ne sera pas affiché\n";
} catch (\Throwable $ex) {
// \Throwable, çoğu hata ve istisna tarafından uygulanan arayüzdür
// istisna görüntülenir
print "erreur, message : " . $ex->getMessage() . ", type : " . get_class($ex) . "\n";
}
Açıklamalar
- Bu komut dosyası, önceki paragrafta sunulan komut dosyasıdır. Ancak şimdi, hata oluşturma olasılığı bulunan 8-19. satırlardaki kod, bir try / catch yapısı ile çevrelenmiştir: 8-21. satırlardaki kod bir istisna veya hata oluşturursa (atarsa), bu durum 22-26. satırlardaki catch cümlesi tarafından yönetilecektir;
- 22. satır: [catch] cümlesindeki parametre, yönetmek istediğimiz istisna veya hata türüdür. Bir arayüz olan [\Throwable] türünü belirleyerek, [\Throwable] arayüzünü uygulayan tüm sınıf örneklerini yönetmek istediğimizi belirtiriz. Tüm hata ve istisna sınıfları bu arayüzü uyguladığından, [catch] cümlesi burada bir sınıf içinde kapsüllenmiş tüm hataları/istisnaları yönetir;
- 19. satır: hatayı tetikleyen ve istisnayı oluşturan komut. Bir istisna oluştuğu anda, [catch] cümlesine yönlendirme yapılır. Dolayısıyla, 19. satırın sonrasındaki kod yürütülmeyecektir;
Sonuçlar
Sonuçlara ilişkin açıklamalar
- 1. ve 3. satırlar: [E_NOTICE] ve [E_WARNING] düzeyindeki hatalar görülmektedir. Bu hatalar istisna değildir ve bu nedenle [catch] cümlesi tarafından yönetilmez;
- 5. satır: [catch] cümlesinde yazan hata mesajı görülüyor. Dolayısıyla, [\Exception]’ten türetilen bir istisna ya da [\Error]’ten türetilen bir hata meydana gelmiştir. Burada bunun [\RuntimeException] sınıfına ait olduğunu görüyoruz;
7.7. [catch] cümlesinin parametreleri
Aşağıdaki [exceptions-03.php] komut dosyasını inceleyelim:
<?php
// tüm hatalar görüntülenir
ini_set("error_reporting", E_ALL);
ini_set("display_errors", "on");
// sabit sınırlı bir dizi
$array = new \SplFixedArray(5);
try {
// sınırların dışındaki indeks
$array[5] = 8;
} catch (\Throwable $ex) {
// hata mesajı görüntüleme
print "Erreur 1 : " . $ex->getMessage() . "\n";
}
try {
// sınırların dışında bir indeks
$array[5] = 8;
} catch (\Exception $ex) {
// hata mesajı göstergesi
print "Erreur 2 : " . $ex->getMessage() . "\n";
}
try {
// değer sınırların dışında
$array[5] = 8;
} catch (\RuntimeException $ex) {
// hata mesajı görüntüleme
print "Erreur 3 : " . $ex->getMessage() . "\n";
}
try {
// 0 ile bölme
intdiv(5, 0);
} catch (\Throwable $ex) {
// hata mesajı görüntüleme
print "Erreur 4 : " . $ex->getMessage() . "\n";
}
try {
// 0 ile bölme
intdiv(5, 0);
} catch (\DivisionByzeroError $ex) {
// hata mesajı görüntüleme
print "Erreur 5 : " . $ex->getMessage() . "\n";
}
try {
// 0 ile bölme
intdiv(5, 0);
} catch (\Error $ex) {
// hata mesajı görüntüleme
print "Erreur 6 : " . $ex->getMessage() . "\n";
}
try {
// 0 ile bölme
intdiv(5, 0);
} catch (\Exception $ex) {
// hata mesajı görüntüleme
print "Erreur 6 : " . $ex->getMessage() . "\n";
}
Açıklamalar
- 8-31. satırlar: [\SplFixedArray] sınıfında yanlış bir indeks kullanılması sonucu ortaya çıkan istisnayı yönetmenin 3 farklı yolu. Bu hatanın [RuntimeException] türünde bir istisna oluşturduğunu görmüştük;
- 12. satır: [\Throwable] türünde bir hatayı işler. [RuntimeException] türü, [\Exception] türünden türetilmiş ve bu tür de [\Throwable] arayüzünü uyguladığından, bu geçerlidir;
- 20. satır: [\Exception] türündeki bir hatayı işler. [RuntimeException] türü, [\Exception] türünden türetildiğinden bu geçerlidir;
- 28. satır: [\RuntimeException] türündeki bir hatayı işler. Oluşturulan istisnanın tam türü bu olduğu için tercih edilmesi gereken yöntem budur;
- 32-62. satırlar: [intdiv] işlevine 0'a eşit bir bölücü aktarıldığında bu işlev tarafından oluşturulan istisnayı yönetmenin 4 farklı yolu. [ intdiv ( int $dividend , int $divisor ) : int] fonksiyonu, $dividend / $divisor tam sayı bölme işlemini gerçekleştirir. Bölücü sıfır olduğunda, [\DivisionByzeroError] istisnası tetiklenir;
- 35. satır: [\Throwable] arayüzünü uygulayan tüm hatalar yakalanır. Bu geçerlidir;
- 43. satır: hatanın tam türü yakalanır: tercih edilmesi gereken yöntem budur;
- 51. satır: [\Error] türü yakalanır. [DivisionByzeroError] sınıfı, [Error] sınıfını genişlettiği için bu geçerlidir;
- satır 59: [\Exception] türü yakalanır. [DivisionByzeroError] sınıfının [\Exception] sınıfıyla hiçbir bağlantısı olmadığı için bu geçersizdir;
Sonuçlar
7.8. [finally] maddesi
try / catch yapısı üçüncü bir öğeye sahip olabilir ve try / catch / finally yapısına dönüşebilir. [finally] cümlesindeki kod, aşağıdaki iki durumda da yürütülür:
- [try] cümlesi bir istisna oluşturmaz. Bu durumda tamamen yürütülür ve ardından kodun yürütülmesi, tamamen yürütülen [finally] cümlesine geçer;
- [try] cümlesi bir istisna oluşturur. Bu durumda, istisnayı oluşturan komuta kadar yürütülür. Kodun yürütülmesi daha sonra [catch] maddesine geçer ve bu madde tamamen yürütülür. Ardından kodun yürütülmesi [finally] maddesine geçer ve bu madde tamamen yürütülür;
Son olarak, [finally] cümlesindeki kod da her zaman yürütülür. Bu senaryo aşağıdaki durumda yararlıdır:
- [try]'te kod, kaynaklar (dosyalar, veritabanları, ağ bağlantıları, kuyruklar) elde etmiştir. Genellikle bu kaynaklar bellek açısından yük oluşturur. Bu nedenle, mümkün olan en kısa sürede bu kaynaklar iade edilmelidir (genellikle "kapatmak" olarak ifade edilir);
- kaynakların edinilmesi [try]'te gerçekleştirildiyse, bunların iadesi [finally]'te yapılır. Bu, her durumda (hata olsun ya da olmasın) edinilen kaynakların sisteme iade edilmesini garanti eder;
Aşağıdaki [exemples/exceptions/exceptions-04.php] komut dosyası, [finally] maddesinin çeşitli durumlarda nasıl işlediğini göstermektedir:
<?php
// veya bir istisna örneği oluşturur
$e = new \Exception("Erreur…");
var_dump($e);
// ilk test
try {
print "Premier test\n";
throw $e;
} catch (\Exception $ex1) {
print $ex1->getMessage() . "\n";
} finally {
print "Terminé\n";
}
// ikinci test
try {
print "Second test\n";
} catch (\Exception $ex1) {
print $ex1->getMessage() . "\n";
} finally {
print "Terminé\n";
}
// üçüncü test
try {
print "Troisième test\n";
return;
} catch (\Exception $ex1) {
print $ex1->getMessage() . "\n";
} finally {
print "Terminé\n";
}
Kod açıklamaları
- 4. satır: $e, önceden tanımlanmış [\Exception] sınıfının bir örneğidir. Bunu farklı yerlerde çalıştıracağız;
- 8-15. satırlar: $e istisnası, [try] içinde (10. satır) tetiklenir;
- 11. satır: [\Exception] istisnası yakalanır ve hata mesajı konsola yazılır;
- satır 13-15: [finally] yorumu bir mesaj yazar. Yukarıda belirtildiği gibi, bu mesaj, [try]'te hata olsun ya da olmasın her zaman yazılmalıdır;
- 18-24. satırlar: [try]'te hata yok. Burada da [finally]'e geçilmesi gerekir;
- 27-34. satırlar: try bloğunda bir [return] komutu var ve hata yok. Bu durumda, [finally] bloğuna geçilip geçilmeyeceği sorusu akla gelebilir. Yürütme sonucu, evet geçildiğini gösteriyor;
Sonuçlar
Başka bir durumu inceleyelim: [exceptions-05.php]:
<?php
// dördüncü test
try {
print "Quatrième test\n";
exit;
} finally {
print "Terminé\n";
}
Yorumlar
- 6. satır: [exit] komutu, betiğin yürütülmesini derhal durdurur: [finally] bloğu yürütülmez;
- 4-9. satırlar: [catch] cümlesi içermeyen bir try / catch / finally örneği. Bu mümkündür;
Sonuçlar
7.9. Kendi istisna sınıflarınızı oluşturma
Biraz büyük bir projede, farklı hataları farklı istisna sınıfları içinde kapsülleyerek birbirinden ayırmak yararlıdır. Önceki komut dosyasında, her istisnanın bir [catch (\Throwable] cümlesi ile yakalanabileceğini gördük. Yakalanan hatanın ne olduğu hakkında hiçbir fikriniz yoksa ve tüm hatalar için işleme aynıysa bu yöntem önerilir. Bazen durum böyledir, ancak çoğu zaman işlemeyi hatanın tam türüne göre uyarlamak gerekir. Bu durumda hataları birbirinden ayırt etmek gerekir.
Aşağıdaki [exceptions-06.php] komut dosyasını inceleyelim:
<?php
// kendi istisna ailemizi tanımlıyoruz
class Exception1 extends \RuntimeException {
}
class Exception2 extends \RuntimeException {
}
// veya istisnalarımızı kullanıyoruz
$e1 = new Exception1("Erreur1…");
var_dump($e1);
$e2 = new Exception2("Erreur2…");
var_dump($e2);
// birinci test
print ("premier test\n");
try {
// Exception1 türünü tetikliyoruz
throw $e1;
} catch (Exception1 $ex1) {
print "Exception 1" . "\n";
print $ex1->getMessage() . "\n";
} catch (Exception2 $ex2) {
print "Exception 2" . "\n";
print $ex2->getMessage() . "\n";
}
// ikinci test
print ("second test\n");
try {
// Exception2 türünde bir istisna oluşturuyoruz
throw $e2;
} catch (Exception1 $ex1) {
print "Exception 1" . "\n";
print $ex1->getMessage() . "\n";
} catch (Exception2 $ex2) {
print "Exception 2" . "\n";
print $ex2->getMessage() . "\n";
}
// üçüncü test
print ("troisième test\n");
try {
// Exception1 türü bir istisna atılıyor
throw $e1;
} catch (Exception1 | Exception2 $ex) {
print "Exception 1 ou 2" . "\n";
print $ex->getMessage() . "\n";
}
// dördüncü test
print ("quatrième test\n");
try {
// Exception2 türü bir istisna atılıyor
throw $e2;
} catch (Exception1 | Exception2 $ex) {
print "Exception 1 ou 2" . "\n";
print $ex->getMessage() . "\n";
}
Açıklamalar
- 4-10. satırlar: Her ikisi de önceden tanımlanmış [\RuntimeException] sınıfından türetilen [Exception1] ve [Exception2] adlı iki sınıf tanımlanmaktadır. Bu sınıfların gövdesi boştur. Başka bir deyişle, bunlar yalnızca türleri için kullanılır: bu iki istisnayı [catch] cümlelerinde birbirinden ayırt edebilmemiz, türlerinin farklı olmasından kaynaklanmaktadır;
- 13-16. satırlar: sırasıyla [Exception1] ve [Exception2] türlerine sahip iki değişken, $e1 ve $e2 tanımlanmıştır;
- 20-29. satırlar: Bir try / catch / catch yapısı vardır. Bu, farklı [catch] cümleleriyle farklı istisna türlerini yönetmeye olanak tanır;
- 23. satır: [Exception1] türündeki istisnaları yakalar;
- 26. satır: [Exception2] türündeki istisnaları yakalar;
- 49. satır: [Exception1] veya (|) [Exception2] türündeki istisnaları yakalar;
Sonuçlar
Sonuçlara ilişkin açıklamalar
- satır 1-17: bir istisnanın ‘içeriği’:
- 2-3. satırlar: hata mesajı;
- 6-7. satırlar: hata kodu;
- satır 8-9: istisnanın meydana geldiği dosyanın adı;
- satır 10-11: istisnanın meydana geldiği satır;
- satır 15-16: önceki istisna. Bir istisna, başka bir istisnayı kapsayabilir ve böylece bir istisna yığını oluşturabilir. [previous] özniteliği, bu yığını kullanmaya olanak tanır;
7.10. Bir istisnayı yeniden çalıştırma
Aşağıdaki [exceptions-07.php] komut dosyasında gösterildiği gibi, bir istisna birden fazla kez tetiklenebilir:
<?php
try {
try {
// bir istisna atılıyor
throw new \Exception("test");
} catch (\Exception $ex) {
// yakalanan istisna yeniden atılıyor
throw $ex;
} finally {
// finally bloğuna sorunsuzca geçiliyor
print "finally 1\n";
}
} catch (\Exception $ex2) {
// ilk istisna başarıyla yakalanıyor
print $ex2->getMessage() . " dans try / catch / finally externe\n";
} finally {
// finally bloğuna sorunsuzca geçilecek
print "finally 2\n";
}
Açıklamalar
- 6. satır: bir istisna atılır;
- 7. satır: istisna yakalanır;
- 9. satır: istisna yeniden atılır. Ardından, üst düzeydeki try / catch / finally yapısına geçer;
- 14. satır: istisna yeniden yakalanır;
- satır 10-12: Yürütme, 9. satırdaki [throw]'ten sonra bile try / catch / finally yapısının [finally] kısmına geçildiğini göstermektedir;
Sonuçlar
7.11. İstisna yığınının kullanımı
Bir istisna, başka bir istisnayı kapsayabilir; bu istisna da başka bir istisnayı kapsayabilir ve sonuçta bir istisna yığını oluşur. İşte bir örnek [exceptions-08.php]:
Açıklamalar
- 4-14. satırlar: önceden tanımlanmış [RuntimeException] istisnasından türetilen üç istisna sınıfını tanımlar;
- 17. satır: [Exception3] sınıfının bir örneği, [Exception2] sınıfının bir örneği içinde kapsüllenmiştir; bu da [Exception1] sınıfının bir örneği içinde kapsüllenmiştir. Burada kullanılan oluşturucu, [Exception] sınıfının oluşturucusudur:
![]()
Oluşturucunun 3. parametresi, bir istisnayı kapsüllemeye olanak tanır. Bu, aşağıdaki senaryoda yararlı olabilir:
- örneğin bir arayüzle uyumluluk nedeniyle, yalnızca [Exception1] türünde bir istisna üretebilen bir M yöntemi tanımlanır;
- ancak M yönteminde başka türde istisnalar da meydana gelebilir. Bir hatayı M yöntemini çağıran koda iletmek için, bu istisnaları [Exception1] türünde kapsülleyip bu istisnayı atarız. Bu, kapsüllenmiş istisnada bulunan ve hatanın asıl nedeni olan bilginin kaybolmamasını sağlar;
- 20-27. satırlar, bir istisna içindeki iç istisna yığınını nasıl yöneteceğimizi gösterir;
Sonuçlar
object(Exception1)#1 (7) {
["message":protected]=>
string(11) "Erreur 1…"
["string":"Exception":private]=>
string(0) ""
["code":protected]=>
int(1)
["file":protected]=>
string(76) "C:\Data\st-2019\dev\php7\php5-exemples\exemples\exceptions\exceptions-08.php"
["line":protected]=>
int(17)
["trace":"Exception":private]=>
array(0) {
}
["previous":"Exception":private]=>
object(Exception2)#2 (7) {
["message":protected]=>
string(11) "Erreur 2…"
["string":"Exception":private]=>
string(0) ""
["code":protected]=>
int(2)
["file":protected]=>
string(76) "C:\Data\st-2019\dev\php7\php5-exemples\exemples\exceptions\exceptions-08.php"
["line":protected]=>
int(17)
["trace":"Exception":private]=>
array(0) {
}
["previous":"Exception":private]=>
object(Exception3)#3 (7) {
["message":protected]=>
string(11) "Erreur 3…"
["string":"Exception":private]=>
string(0) ""
["code":protected]=>
int(0)
["file":protected]=>
string(76) "C:\Data\st-2019\dev\php7\php5-exemples\exemples\exceptions\exceptions-08.php"
["line":protected]=>
int(17)
["trace":"Exception":private]=>
array(0) {
}
["previous":"Exception":private]=>
NULL
}
}
}
Erreur 1…
Erreur 2…
Erreur 3…