Menu

PHP try catch: İstisna Yakalama, finally ve Throwable

PHP'de başarısız olabilecek kod bir try { } bloğuna girer ve hata fırlatırsa catch (Exception $e) { } çalışır; neden $e->getMessage() içindedir. Birkaç istisna türünü yakalamayı, finally bloğunu, catch (Exception) ifadesinin neden TypeError ve DivisionByZeroError hatalarını kaçırdığını (Throwable yakalayın), yeniden fırlatmayı ve global bir işleyiciyi öğrenin.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

PHP'de başarısız olabilecek kodu try { ... } içine koyar ve başarısızlığı catch (Exception $e) { ... } içinde ele alırsınız. try bloğundaki herhangi bir şey hata fırlatırsa PHP doğrudan eşleşen catch bloğuna atlar ve $e->getMessage() neyin yanlış gittiğini söyler. Hiçbir şey fırlatılmazsa catch bloğu atlanır.

divide(10, 0) ifadesini divide(10, 5) yapın ve tekrar çalıştırın: istisna olmaz, bu yüzden not printed yazdırılır ve catch bloğu atlanır. try olmasaydı istisna betiği ölümcül bir "Uncaught" hatasıyla bitirirdi. Kendi istisnalarınızı fırlatmak ve istisna sınıfları yazmak istisnalar sayfasında.

try catch söz dizimi

Tam biçimin üç parçası vardır. Yalnızca try ile birlikte en az bir catch veya bir finally zorunludur:

try {
    // code that may throw
} catch (SomeException $e) {
    // runs if SomeException (or a subclass) was thrown
} catch (OtherException | ThirdException $e) {
    // runs for either of these types
} finally {
    // always runs, thrown or not
}

catch içindeki tür neyi yakalayacağını belirler: sınıfın kendisini ve onu genişleten her sınıfı. PHP 8.0'dan beri ihtiyacınız olmadığında değişken isteğe bağlıdır: catch (JsonException) { ... }.

Exception, Error ve Throwable yakalama

PHP 7'den beri PHP'nin kendisinin tespit ettiği başarısızlıklar (olmayan bir metodu çağırmak, yanlış bir argüman türü, sıfıra bölme) Exception değil Error fırlatır ve PHP 8 eski uyarıların birçoğunu TypeError ve ValueError hatalarına çevirdi. İkisi de Throwable arayüzünü uygular ama hiçbiri diğerini genişletmez, bu yüzden catch (Exception $e) bir Error yakalamaz:

Throwable
├── Exception                 (problems a program expects and handles)
│   ├── InvalidArgumentException, RuntimeException, JsonException, ...
└── Error                     (engine errors, usually a bug in the code)
    ├── TypeError
    ├── ValueError
    ├── ArithmeticError
    │   └── DivisionByZeroError
    └── UnhandledMatchError, ...

Her sorunu hangi catch bloğunun ele aldığını görmek için bunu çalıştırın:

Peki hangisini yakalamalısınız?

  • Neyin yanlış gidebileceğini ve ne yapılacağını bildiğinizde catch (SomeSpecificException $e). Kodların çoğu böyledir.
  • "Bir kütüphanenin veya kodumun bilerek fırlattığı her şey" için catch (Exception $e).
  • En dış seviyede (bir istek işleyici, bir iş çalıştırıcı) PHP'nin kendi hataları dahil her başarısızlığı loglamak ve dostça bir mesaj göstermek için catch (Throwable $e).

Birden çok istisna türünü yakalama

Farklı türleri farklı şekilde ele almak için birkaç catch bloğu yazın. PHP onları yukarıdan aşağıya dener ve ilk eşleşmeyi kullanır, bu yüzden belirli bir tür kendi üst sınıfından önce gelmelidir, yoksa üst sınıf önce her şeyi yakalar. Birkaç tür aynı muameleyi gördüğünde onları | ile tek bir catch içinde birleştirin:

Üç sınıf da Exception sınıfını genişletir, bu yüzden tek bir catch (Exception $e) de onları yakalardı, ama o zaman kod birine 404, diğerlerine 400 yanıtı veremezdi.

finally: her zaman çalışan kod

Bir finally bloğu, try ve catch nasıl biterse bitsin onlardan sonra çalışır: normal olarak, yakalanan bir istisnayla, kimsenin yakalamadığı bir istisnayla ya da bir return ile. try bloğunun edindiği her şeyi bırakmanın yeridir: bir dosyayı kapatmak, bir kilidi serbest bırakmak, bir zamanlayıcıyı durdurmak.

good.txt için dosya saved yazdırılmadan önce kapanır, çünkü finally fonksiyon gerçekten dönmeden önce çalışır. bad.txt için process() içinde catch yoktur: finally dosyayı kapatır, sonra istisna çağıranın catch bloğuna kadar devam eder.

finally içinde return kullanmaktan kaçının: try bloğunun döndürdüğü değeri değiştirir ve dışarı çıkmakta olan bir istisnayı sessizce yok eder:

function f(): string
{
    try {
        return 'from try';
    } finally {
        return 'from finally';
    }
}

function g(): string
{
    try {
        throw new RuntimeException('lost');
    } finally {
        return 'no exception reaches the caller';
    }
}

echo f(); // from finally
echo g(); // no exception reaches the caller

Bir istisnayı yeniden fırlatma veya sarmalama

Bazen bir catch bloğu bir sorunu yalnızca kısmen ele alabilir: loglar, temizler, sonra devam etmesine izin verir. throw $e; aynı istisnayı yeniden fırlatır. Daha sık olarak orijinal nedeni koruyarak bağlam eklemek istersiniz; üçüncü yapıcı argümanı $previous bunun içindir:

Çağıran tek bir ConfigException ile uğraşır ve yapılandırmanın JSON olduğunu bilmesi gerekmez; getPrevious() ise düşük seviyeli ayrıntıyı log için saklar.

Yakalanmamış istisnalar ve global bir işleyici

Hiçbir catch bloğunun ele almadığı bir istisna betiği sınıfı, mesajı, dosyayı ve satırı ve bir yığın izini içeren ölümcül bir hatayla bitirir:

<?php
// No try/catch anywhere in this file
function charge(int $cents): void
{
    if ($cents <= 0) {
        throw new DomainException("Amount must be positive, got $cents");
    }
}

charge(500);
echo "first charge ok\n";
charge(-1);
echo "never printed\n";

PHP first charge ok yazdırır ve ardından:

PHP Fatal error:  Uncaught DomainException: Amount must be positive, got -1 in /home/index.php:6
Stack trace:
#0 /home/index.php(12): charge()
#1 {main}
  thrown in /home/index.php on line 6

Canlı bir sitede bu mesaj ziyaretçilere asla ulaşmamalıdır. set_exception_handler() kimsenin yakalamadığı her istisnayı alan bir fonksiyon kaydeder; onu loglamak ve kibar bir sayfa yazdırmak için tek bir yer:

İşleyici çalışır ve ardından betik durur; throw sonrasında devam etmenin yolu yoktur. PHP'nin kendi hata metninin sayfada gösterilip gösterilmeyeceğini hata raporlama sayfasında anlatılan display_errors belirler.

Uyarılar istisna değildir

try/catch yalnızca fırlatılan şeyleri görür. Birçok eski PHP fonksiyonu hata fırlatmaz: false veya null döndürür ve en fazla bir uyarı yazdırır. json_decode() tipik bir örnektir ve siz ondan hata fırlatmasını isteyene kadar onu try ile sarmak hiçbir şeyi değiştirmez:

Böyle bir bayrağı olmayan fonksiyonlarda dönüş değerini kontrol edin (if ($handle === false)) ya da önce ön koşulu kontrol edin (file_exists(), isset()). ErrorException fırlatan bir set_error_handler(), her şey için tek bir kural istiyorsanız her uyarıyı gerçek bir istisnaya çevirir.

Tarif: form girdisini istisnalarla doğrulama

Pratik bir kalıp: doğrulama fonksiyonları hata fırlatır, sayfa onu yakalar ve mesajı formun yanında gösterir. Çalıştırın, sonra forma bir yaş yazın ve Send düğmesine basın: aynı betik $_POST doldurulmuş olarak yeniden çalışır.

Boş bir alanı, twelve, 9 ve 30 değerlerini deneyin. Başarısız olan her kural kendi mesajıyla hata fırlatır ve tek bir catch hepsini aynı kırmızı satıra çevirir. Formlar sayfası bunun üzerine birkaç alan ve her birinin yanında hatalarla inşa eder.

Sıkça Sorulan Sorular

PHP'de try catch nasıl çalışır?

PHP try { } içindeki kodu çalıştırır. İçindeki bir şey hata fırlatırsa PHP try bloğunun geri kalanını atlar ve türü eşleşen ilk catch bloğunu, fırlatılan nesne değişkende olacak şekilde çalıştırır: catch (Exception $e) { echo $e->getMessage(); }. Hiçbir şey fırlatılmazsa catch blokları atlanır.

PHP'de tüm istisnaları ve hataları nasıl yakalarım?

Throwable yakalayın: catch (Throwable $e). catch (Exception $e) yalnızca istisnaları yakalar, Error sınıfını genişleten TypeError, ValueError veya DivisionByZeroError gibi motor hatalarını yakalamaz. Exception ve Error ikisi de Throwable arayüzünü uygular.

PHP'de tek bir catch bloğunda birden çok istisnayı nasıl yakalarım?

Türleri dikey çizgiyle ayırın: catch (InvalidArgumentException | RangeException $e). Birbiri ardına birkaç catch bloğu da yazabilirsiniz; PHP eşleşen ilkini kullanır, bu yüzden en belirli türleri önce koyun.

try içinde return varsa finally çalışır mı?

Evet. finally, try ve catch sonrasında kod ister döndürmüş, ister hata fırlatmış, ister normal bitmiş olsun çalışır; try bir return içerdiğinde de. finally kendisi bir değer döndürürse o değer try bloğundan geleni değiştirir, bu yüzden finally içinde return kullanmaktan kaçının.

PHP'de try catch uyarıları yakalar mı?

Hayır. Uyarılar ve bildirimler (eksik bir dizi anahtarını okumak gibi) istisna değildir, bu yüzden catch onları asla görmez. Çağrıdan önce koşulu kontrol edin, fonksiyonun varsa istisna modunu kullanın (json_decode(..., flags: JSON_THROW_ON_ERROR)) ya da uyarıları set_error_handler() ve ErrorException ile dönüştürün.

Coddy programlama dilleri çizimi

Coddy ile kodlamayı öğren

BAŞLA