Menangani Kesalahan Dalam PHP Saat Menggunakan MVC

12

Saya telah menggunakan Codeigniter baru-baru ini, tetapi satu hal yang membuat saya gugup adalah menangani kesalahan dan menampilkannya kepada pengguna. Saya tidak pernah pandai menangani kesalahan tanpa menjadi berantakan. Perhatian utama saya adalah ketika mengembalikan kesalahan kepada pengguna.

Apakah praktik yang baik untuk menggunakan pengecualian dan melempar / menangkap pengecualian daripada mengembalikan 0 atau 1 dari fungsi dan kemudian menggunakan if / else untuk menangani kesalahan. Dengan demikian, membuatnya lebih mudah untuk memberi tahu pengguna tentang masalah tersebut.

Saya cenderung menjauh dari pengecualian. Tutor Java saya di universitas beberapa tahun yang lalu memberi tahu saya "pengecualian tidak boleh digunakan dalam kode produksi, ini lebih untuk debugging". Saya merasa dia berbohong.

Tapi, contohnya, saya punya kode yang menambahkan pengguna ke database. Selama proses lebih dari 1 hal bisa salah, seperti masalah database, entri duplikat, masalah server, dll. Ketika masalah terjadi saat pendaftaran, pengguna perlu tahu tentang hal itu.

Apa cara terbaik untuk menangani kesalahan dalam PHP, mengingat bahwa saya menggunakan kerangka kerja MVC.

James Jeffery
sumber

Jawaban:

14

Apakah praktik yang baik untuk menggunakan pengecualian dan melempar / menangkap pengecualian daripada mengembalikan 0 atau 1 dari fungsi dan kemudian menggunakan if / else untuk menangani kesalahan. Dengan demikian, membuatnya lebih mudah untuk memberi tahu pengguna tentang masalah tersebut.

Tidak tidak Tidak!

Jangan gabungkan pengecualian dan kesalahan. Pengecualian, yah, luar biasa. Kesalahan tidak. Saat Anda meminta pengguna untuk memasukkan jumlah produk, dan pengguna memasukkan "halo", itu adalah kesalahan. Ini bukan pengecualian: tidak ada yang luar biasa dalam melihat input yang tidak valid dari pengguna. Mengapa Anda tidak dapat menggunakan pengecualian dalam kasus yang tidak biasa, seperti saat memvalidasi input? Orang lain sudah menjelaskannya, dan menunjukkan alternatif valid untuk input validasi.

Ini juga berarti bahwa pengguna tidak peduli tentang pengecualian Anda , dan menunjukkan pengecualian itu tidak ramah dan berbahaya . Misalnya, pengecualian selama eksekusi query SQL sering mengungkapkan query itu sendiri. Yakin ingin mengambil risiko untuk menampilkan pesan seperti itu kepada semua orang?

lebih dari 1 hal bisa salah, seperti masalah basis data, entri duplikat, masalah server, dll. Ketika masalah terjadi saat pendaftaran, pengguna harus mengetahuinya.

Salah. Sebagai pengguna, saya tidak perlu tahu masalah basis data Anda, entri rangkap, dll. Saya benar-benar tidak peduli dengan masalah Anda . Apa yang saya lakukan perlu tahu adalah bahwa saya masuk username yang sudah ada. Seperti yang sudah dikatakan, input yang salah dari saya harus memicu kesalahan, bukan pengecualian.

Bagaimana cara menghasilkan kesalahan itu? Itu tergantung pada konteksnya. Untuk nama pengguna yang sudah digunakan, saya ingin melihat bendera merah kecil muncul di dekat nama pengguna, bahkan sebelum mengirimkan formulir, mengatakan bahwa nama pengguna sudah digunakan. Tanpa JavaScript, bendera yang sama harus muncul setelah pengiriman.

Contoh kesalahan yang diaktifkan AJAX

Untuk kesalahan lain, Anda akan menampilkan satu halaman penuh dengan kesalahan, atau memilih cara lain untuk memberi tahu pengguna bahwa ada kesalahan (misalnya pesan yang akan muncul, kemudian menghilang di bagian atas halaman). Pertanyaannya kemudian lebih terkait dengan pengalaman pengguna daripada pemrograman.

Dari sudut pandang programmer, tergantung dari jenis kesalahan, Anda akan menyebarkannya dengan cara yang berbeda. Misalnya, dalam kasus nama pengguna sudah diambil, permintaan AJAX untuk http://example.com/?ajax=1&user-exists=Johnakan mengembalikan objek JSON yang menunjukkan:

  • Bahwa pengguna sudah ada,
  • Pesan kesalahan ditampilkan kepada pengguna.

Poin kedua penting: Anda ingin memastikan bahwa pesan yang sama muncul baik ketika mengirimkan formulir dengan JavaScript dinonaktifkan dan mengetik nama pengguna duplikat dengan JavaScript diaktifkan. Anda tidak ingin menduplikasi teks pesan kesalahan dalam kode sumber sisi server dan dalam JavaScript!

Ini sebenarnya teknik yang digunakan oleh situs web Stack Exhange. Sebagai contoh jika saya mencoba untuk memvotasikan jawaban saya sendiri, respons AJAX berisi kesalahan untuk ditampilkan:

{"Success":false,"Warning":false,"NewScore":0,"Message":"You can't vote for your own post.",
"Refresh":false}

Anda juga dapat memilih pendekatan lain, dan mempraset kesalahan di halaman HTML sebelum formulir diisi. Pro: Anda tidak perlu mengirim pesan kesalahan dalam respons AJAX. Cons: bagaimana dengan aksesibilitas? Cobalah menelusuri halaman tanpa CSS, dan Anda akan melihat semua kesalahan yang mungkin muncul.

Arseni Mourzenko
sumber
Saya menghargai tanggapannya. Inilah tepatnya yang saya perjuangkan. Apakah Anda memiliki sumber daya tentang kesalahan pelaporan, terutama dalam hal pengalaman pengguna?
James Jeffery
Yah, seperti yang saya katakan, itu benar-benar tergantung pada kesalahan, dan pelaporan kesalahan kepada pengguna sangat terkait dengan antarmuka pengguna. Saya juga menyoroti dua cara utama untuk melaporkan kesalahan: integrasi ketat (bendera merah berkemampuan AJAX dekat input dengan nilai yang salah) dan kesalahan satu halaman penuh, jauh lebih tidak bersahabat, digunakan untuk kasus yang lebih parah. Bukankah ini menjawab pertanyaan Anda?
Arseni Mourzenko
2
+1 karena lebih merupakan masalah pengalaman pengguna dan bukan masalah teknis
Charles Sprayberry
2
Omong kosong, MainMa. Hanya omong kosong. Kode kesalahan sangat 80-an dan 90-an. Pengecualian adalah cara yang jauh lebih bersih untuk menangani keadaan khusus seperti input yang salah (ValidationException misalnya). Anda tidak dipaksa untuk menampilkan setiap pengecualian kepada pengguna. Saya telah melihat jawaban Anda yang lebih baik.
Falcon
2
Dan untuk berjaga-jaga jika Anda tidak mengetahuinya: Anda dapat mengontrol pengecualian mana yang ingin Anda tampilkan kepada pengguna dan yang tidak ingin Anda tampilkan. Jadi itu sama sekali bukan argumen.
Falcon
13

Apakah praktik yang baik untuk menggunakan pengecualian dan melempar / menangkap pengecualian daripada mengembalikan 0 atau 1 dari fungsi dan kemudian menggunakan if / else untuk menangani kesalahan. Dengan demikian, membuatnya lebih mudah untuk memberi tahu pengguna tentang masalah tersebut.

Ya ya ya!

Jika Anda ingin memiliki kode bersih, Anda harus hampir secara eksklusif menggunakan pengecualian dan jangan repot-repot menggunakan kode kesalahan. Kode kesalahan tidak ada artinya. Mereka hampir selalu terikat pada konstanta numerik yang tidak mengungkapkan banyak informasi. Ini dapat membuat kode Anda tidak dapat dibaca dan mereka akan membuatnya sulit untuk menyebarkan data di samping kesalahan.

Namun, pengecualian adalah kelas dan dapat berisi informasi apa pun yang Anda suka. Jadi pengguna memasukkan input yang salah, seperti 'abc' untuk bidang angka. Dengan kode kesalahan Anda tidak akan dapat menyebarkan informasi ini ke penangan kesalahan tanpa banyak gelembung. Sesuatu yang disediakan pengecualian gratis. Selain itu, pengecualian memungkinkan Anda untuk memiliki nilai balik yang bermakna dalam fungsi dan metode sambil tetap memiliki cara gagal secara elegan. Bahkan lebih baik lagi, Pengecualian disebarkan ke tempat Anda ingin menanganinya! Bayangkan jumlah kode spageti yang Anda perlukan untuk menyebarkan kode kesalahan dengan data yang bermakna ke penangan satu atau dua lapisan di atas.

Juga, pengecualian menyatakan jauh lebih semantik daripada kode kesalahan. Kode kesalahan mengarah ke kode spaghetti di mana penanganan pengecualian mengarah ke kode bersih.

Selain itu, mudah untuk lupa memeriksa kode status. Dalam bahasa seperti Java Anda terpaksa menangani pengecualian (sesuatu yang misalnya C # misses).

Apa cara terbaik untuk menangani kesalahan dalam PHP, mengingat bahwa saya menggunakan kerangka kerja MVC.

Gunakan pengecualian dan tangani di pengontrol Anda.

Elang
sumber
Saya sangat setuju dengan Anda !! Meskipun pengecualian tidak berlaku dan PHP seperti dalam bahasa lain, baik untuk mengetahui bahwa banyak orang memasukkannya ...
David Conde
6
Saya setuju bahwa dalam kebanyakan kasus kode kesalahan cukup tidak berarti. Namun, melempar pengecualian mau tak mau sangat buruk! Pengecualian harus disediakan hanya untuk keadaan luar biasa. Pengecualian menyebabkan aliran program tidak dapat diprediksi, dapat membuat kode sulit untuk diikuti (dan karenanya dipelihara), dan dalam PHP mereka membawa penalti kinerja yang agak signifikan dibandingkan dengan IF / THEN / ELSE. Saya cenderung memilih metode untuk mengembalikan yang benar pada kesuksesan, salah pada kegagalan, dan hanya melemparkan pengecualian pada sesuatu yang salah.
GordonM
6

Pertimbangkan kelas kecil yang berguna ini:

class FunkyFile {               

    private $path;
    private $contents = null;

    public function __construct($path) { 
        $this->setPath($path); 
    }

    private function setPath($path) {
        if( !is_file($path) || !is_readable($path) ) 
            throw new \InvalidArgumentException("Hm, that's not a valid file!");

        $this->path = realpath($path);
        return $this; 
    }

    public function getContents() {
        if( is_null($this->contents) ) {
            $this->contents = @file_get_contents( $this->path );
            if($this->contents === false) 
                throw new \Exception("Hm, I can't read the file, for some reason!");                                 
        }

        return $this->contents;            
    }

}

Itu penggunaan pengecualian yang sangat bagus. Dari FunkyFile'sperspektif sama sekali tidak ada yang dapat dilakukan untuk memperbaiki situasi jika salah jalan tidak valid atau file_get_contentsgagal. Situasi yang benar-benar luar biasa;)

Tetapi apakah ada nilai bagi pengguna Anda untuk mengetahui bahwa Anda menemukan jalur file yang salah, di suatu tempat dalam kode Anda? Sebagai contoh:

class Welcome extends Controller {

    public function index() {

        /**
         * Ah, let's show user this file she asked for
         */                 
        try {
            $file = new File("HelloWorld.txt");
            $contents = $file->getContents();   
            echo $contents;
        } catch(\Exception $e) {
            log($e->getMessage());

            echo "Sorry, I'm having a bad day!"; 
        }                           
    }        
}

Selain memberi tahu orang-orang bahwa Anda mengalami hari yang buruk, pilihan Anda adalah:

  1. Fallback

    Apakah Anda punya cara lain untuk mendapatkan informasi? Dalam contoh sederhana saya di atas, sepertinya tidak mungkin, tetapi pertimbangkan skema master / slave database. Master mungkin gagal merespons tetapi mungkin, mungkin saja, budak masih di luar sana (atau sebaliknya).

  2. Apakah ini kesalahan pengguna?

    Apakah pengguna mengirimkan input yang salah? Nah, katakan padanya tentang itu. Anda bisa menggonggong pesan kesalahan, atau bersikap baik dan menemani pesan kesalahan itu dengan formulir sehingga dia bisa mengetik di jalur yang benar.

  3. Apakah ini salahmu?

    Dan oleh Anda, maksud saya apa pun yang bukan pengguna, sehingga berkisar dari Anda mengetik jalur file yang salah, untuk sesuatu yang serba salah di server Anda. Sebenarnya, sudah waktunya untuk kesalahan HTTP 503 , karena, juga, layanan tidak tersedia. CI memiliki show_404()fungsi, Anda dapat dengan mudah membangun show_503().

Kata nasihat, Anda harus mempertimbangkan pengecualian nakal. CodeIgniter adalah sepotong kode yang berantakan, dan Anda tidak pernah tahu kapan pengecualian akan muncul. Demikian pula, Anda mungkin lupa tentang pengecualian Anda sendiri, dan opsi teraman adalah menerapkan tangkapan semua penangan pengecualian. Di PHP Anda bisa melakukannya dengan set_exception_handler :

function FunkyExceptionHandler($exception) {
    if(ENVIRONMENT == "production") {
        log($e->getMessage());
        show_503();
    } else {
        echo "Uncaught exception: " , $exception->getMessage(), "\n";
    }   
}

set_exception_handler("FunkyExceptionHandler");

Dan Anda juga bisa mengatasi kesalahan jahat, melalui set_error_handler . Anda bisa menulis handler yang sama dengan pengecualian, atau sebagai alternatif mengonversi semua kesalahan ke ErrorExceptiondan membiarkan penanganan handler pengecualian Anda dengan mereka:

function FunkyErrorHandler($errno, $errstr, $errfile, $errline) {
    // will be caught by FunkyExceptionHandler if not handled
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("FunkyErrorHandler");
yannis
sumber
Ini benar-benar informatif, tepuk tangan!
James