Coba / Tangkap blok di PHP tidak menangkap Exception

97

Saya mencoba menjalankan Contoh # 1 ini dari halaman ini: http://php.net/manual/en/language.exceptions.php

<?php
function inverse($x) {
    if (!$x) {
        throw new Exception('Division by zero.');
    }
    return 1/$x;
}
try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}
// Continue execution
echo "Hello World\n";
?>

Namun, alih-alih keluaran yang diinginkan, saya mendapatkan:

0.2
Fatal error: Uncaught exception 'Exception' with message 'Division by zero.' 
in xxx:
7 Stack trace: #0 xxx(14): inverse(0) #1 {main} thrown in xxx on line 7

Lingkungan pengembang yang saya gunakan adalah UniServer 3.5denganPHP 5.2.3

Krassi
sumber
1
Bisakah Anda menunjukkan kode Anda? Satu-satunya kesalahan yang dapat Anda lakukan untuk mendapatkan kesalahan ini adalah menangkap pengecualian yang salah (atau tidak sama sekali).
Tammo
2
Kode PERSIS identik (Saya baru saja menambahkan beberapa baris baru) ... bagaimanapun, saya menyalin kode sekali lagi ke dalam file tes dan berikut adalah pesan kesalahan yang sama: 0,2 Kesalahan fatal: Pengecualian 'Pengecualian' yang tidak tertangkap dengan pesan 'Pembagian oleh nol . ' di W: \ www \ test.php: 4 Pelacakan tumpukan: # 0 W: \ www \ test.php (11): inverse (0) # 1 {main} dilemparkan ke W: \ www \ test.php di baris 4 Saya benar-benar tidak tahu apa yang terjadi di sana ... mungkin konfigurasi PHP salah?
Krassi
1
Beberapa versi ekstensi yang lebih lama menyebabkan masalah dengan penanganan pengecualian. 5.2.3 sudah tua dan bug mungkin ada di balik kesalahan ini. Bisakah Anda meningkatkan PHP? UniServer 3.5 juga terbilang cukup tua, mengingat versi produksi saat ini adalah 5.5. Apakah 3.5 salah ketik?
keluar
1
Melihat info rilis UniServer ( wiki.uniformserver.com/index.php/… ), 3.5 ternyata bukan salah ketik. Tingkatkan ke UniServer 5.5 dan coba kode sampel lagi.
keluar
1
outis, terima kasih atas tipnya :). Inilah yang saya lakukan saat itu - beralih ke XAMPP (tidak suka versi baru UniServer). 3.5 bukan kesalahan ketik, tetapi server bekerja dengan sempurna untuk saya jadi saya tidak pernah repot memutakhirkannya.
Krassi

Jawaban:

217

Saya baru saja mengalami masalah ini di mana sepertinya saya telah menyalin nama pengecualian, namun tidak menangkapnya. Ternyata itu adalah kesalahan bodoh saya, tetapi saya pikir saya harus memposting kasus saya di sini jika ada orang lain dalam situasi yang sama.

Aku punya pengecualian saya di namespace saya disebut A dan script itu dalam namespace disebut B . Masalahnya adalah saya memiliki A \ MyException yang sama dengan (dalam PHP) \ B \ A \ MyException (karena skrip saya ada di namespace bernama B !). Yang harus saya lakukan untuk memperbaikinya adalah menambahkan garis miring terbalik (atau apa pun namanya) ke nama pengecualian sehingga akan terlihat seperti ini: \ A \ MyException

Pijusn
sumber
7
terima kasih banyak telah memposting ini karena saya akan pergi beberapa hari tanpa menyadari kesalahan saya.
tipu
79
Ini memecahkan masalah saya, blok tangkap malas sederhana dalam kode spasi nama seharusnya catch (\Exception $e). Tanpa garis miring terbalik Exceptionkhusus untuk namespace dan tidak akan cocok (atau tertangkap).
joemaller
3
Terima kasih telah memposting ini!
keepkimi
2
Terima kasih telah memposting ini, saya baru saja menghabiskan beberapa jam terakhir menjadi gila mengapa blok tangkap saya tidak berfungsi. Telapak muka utama.
Mitch
4
Bersulang! Menyelamatkan hari saya (dan neuron ...) :)
sayuran
67

Pertanyaan yang cukup lama, namun ...

Saya mengalami masalah ini juga (dan begitulah cara saya menemukan posting ini) tetapi hanya eksperimen sederhana yang memungkinkan saya menemukan solusinya. Coba saja ubah Exceptionke \Exception. Bekerja untuk saya!

EDIT:

Seperti yang ditunjukkan sivann di komentar, menggunakan namespace harus melakukan hal yang sama. Jadi, letakkan saja use \Exception as Exception;sebelum deklarasi kelas Anda.

Enethion
sumber
Cemerlang! :) Mungkin butuh waktu berjam-jam untuk mengetahuinya, hanya tidak memikirkan namespacing. Terima kasih!
Alexander Gilmanov
Iya! juga: "use \ Exception as Exception;" di atas melakukan hal yang sama.
sivann
@ sii-anik Coba gunakan namespace seperti yang sivann tulis.
Enethion
hanya use Exception;harus melakukannya
Diego Ponciano
Terima kasih! @Enethion
Noamway
32

Cobalah untuk menempatkan, catch(\Exception $e)bukan catch(Exception $e). Jika Anda menggunakan kode yang tidak Anda ketahui dengan baik, atau - terutama - jika Anda menggunakan kerangka kerja, itu mungkin menimpa Pengecualian PHP default dengan salah satunya, dan oleh karena itu Anda mungkin pergi ke jalur yang salah dan mendapatkan hasil yang tidak diinginkan. Jika Anda hanya memasukkan \Exception, maka Anda yakin Anda menangkap pengecualian dasar PHP.

Vladimir Despotovic
sumber
@crassi, apakah Anda mencoba saran saya?
Vladimir Despotovic
2
yang melakukannya untuk saya
cljk
20

Anda tidak bisa menggunakan blok try {} catch {} biasa dalam PHP seperti yang bisa Anda lakukan dalam bahasa lain seperti C # (Csharp).

Jika kamu melakukan ini:

try{
    //division by zero
    $number = 5/0;
}
catch(Exception $ex){
    echo 'Got it!';
}

Anda tidak akan melihat pesan 'Mengerti!' pesan tidak pernah. Mengapa? Itu hanya karena PHP selalu membutuhkan Pengecualian untuk "Dilempar". Anda perlu menyetel penangan kesalahan Anda sendiri dan melemparkan Pengecualian dengannya.

Lihat fungsi set_error_handler : http://php.net/manual/es/function.set-error-handler.php

Rowinson Gallego
sumber
6
Itu tidak sama;) Anda perlu membuat pengecualian sendiri, dan itulah yang saya katakan (<< Ini hanya karena PHP selalu membutuhkan Pengecualian untuk "Dilempar" >>) @JaredFarrish
Rowinson Gallego
Ya, tapi kenapa tidak sama?
Jared Farrish
Tautan itu mati, tetapi saya menemukan ini berguna: w3schools.com/php/func_error_set_error_handler.asp
Membenci
Dalam PHP Versi 7.3.9, $number = 5/0;tidak memunculkan pengecualian. $numberdiatur menjadi INF.
virtualmic
6

Awalnya saya adalah Anda memiliki kesalahan ketik dalam nama pengecualian yang Anda tangkap / lempar, tetapi jika kode Anda persis sama, saya tidak yakin persis apa yang sedang terjadi.

Coba modifikasi berikut dari skrip asli, dan tempelkan hasil Anda. Ini akan membantu mendiagnosis masalah Anda sedikit lebih baik.

<?php

//set up exception handler to report what we didn't catch
function exception_handler($exception) {

    if($exception instanceof MyException) {
        echo "you didn't catch a myexception instance\n";

    } else if($exception instanceof Exception) {
        echo "you didn't catch a exception instance\n";

    } else {
        echo "uncaught exception of type: ".gettype($exception)."\n";
    }

    echo "Uncaught exception: " , $exception->getMessage(), "\n";
}

//install the handler
set_exception_handler('exception_handler');

class MyException extends Exception {
}

function inverse($x) {
    if (!$x) {
        throw new MyException('Division by zero.');
    }
    else return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (MyException $e) {
    echo 'Caught myexception: ',  $e->getMessage(), "\n";
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}

// Continue execution
echo 'Hello World';
?>
sfrench.dll
sumber
4

Saya memiliki masalah yang sama dengan konfigurasi berikut,

PHP 5.2.14 (cli) (dibangun: Agustus 12 2010 17:32:30) Hak Cipta (c) 1997-2010 The PHP Group Zend Engine v2.2.0, Hak Cipta (c) 1998-2010 Zend Technologies dengan eAccelerator v0.9.5. 1 , Hak Cipta (c) 2004-2006 eAccelerator, oleh eAccelerator

Solusinya adalah menonaktifkan eAccelerator atau memperbaruinya. Saya mencoba keduanya dan kedua perbaikan berhasil. Bug dilaporkan di sini https://eaccelerator.net/ticket/242 (NB. Firefox mengeluh tentang sertifikat SSL mereka).

Sekarang saya menjalankan coba tangkap dengan benar dengan konfigurasi berikut,

PHP 5.2.4 (cli) (dibangun: Okt 16 2007 09:13:35) Hak Cipta (c) 1997-2007 The PHP Group Zend Engine v2.2.0, Hak Cipta (c) 1998-2007 Zend Technologies dengan eAccelerator v0.9.6. 1 , Hak Cipta (c) 2004-2010 eAccelerator, oleh eAccelerator

Yawar
sumber
3

di Xdebug ada pengaturan:

xdebug.show_exception_trace = 1

Ini akan memaksa php untuk mengeluarkan pengecualian bahkan dalam blok coba tangkap. Putar ini ke0

pengguna2950254
sumber
2
Dalam kasus saya, saya harus menonaktifkan modul xdebug sepenuhnya (mengubah xdebug.show_exception_trace tidak cukup).
Thomas Sahlin
Terima kasih atas pengingat ini. Saya benar-benar bingung untuk beberapa saat.
Brian Litzinger
3

Jika Anda menggunakan PHP 7, Anda mungkin perlu Throwable, bukan Exception

pengguna5528384
sumber
Ini adalah postingan yang agak lama. Perhatikan tanggal topik sebelum Anda memutuskan untuk menjawab. Selain itu jawaban Anda tidak terlalu membantu karena: - tidak lengkap - tidak ada penjelasan mengapa
monofone
1
Penjelasannya adalah bahwa PHP7 menggunakan Throwable, bukan Exception. Diskusi ini adalah yang pertama kali saya temukan ketika saya menemui masalah dan saya ingin berkontribusi. Komentar seperti ini adalah alasan mengapa Stack tidak ramah komunitas.
pengguna5528384
1
itu bukan niat saya untuk menyinggung perasaan Anda. Posting ini muncul di antrian review "Posting pertama" dan menurut saya tidak berguna untuk mengirim jawaban atas pertanyaan yang agak lama. Dan pada saat penulisan, Question Throwable bahkan tidak ditemukan di dunia PHP. Akan sangat membantu jika Anda menulis dalam jawaban Anda bahwa Throwable adalah Antarmuka yang diimplementasikan oleh Exception (dan Error) dan dengan demikian dapat ditangkap juga. Tapi ini bukan suplemen untuk sebuah Pengecualian.
monofone
1

TLDR; pastikan Anda memiliki use Exception;di bagian atas kedua file php

Tuan Heelis
sumber
0

Saya mengalami ini juga. Saya membaca komentar dari Rowinson Gallego yang menyatakan Exception harus dibuang. Jadi saya mengubah kode saya dari:

try
{
  $number = 5/0; //or other exception
}
catch(Exception $e)
{
  throw $e;
}

menjadi:

try
{
  $number = 5/0; //or other exception
}
catch(Exception $e)
{
  throw new Exception($e->getMessage(),$e->getCode());
}

Berhasil.

Fauzie Adriansyah
sumber