การจัดการข้อผิดพลาดใน PHP เมื่อใช้ MVC


12

ฉันใช้ Codeigniter บ่อยครั้งมาก แต่สิ่งหนึ่งที่ทำให้ฉันกังวลคือการจัดการข้อผิดพลาดและแสดงให้ผู้ใช้เห็น ฉันไม่เคยจัดการกับข้อผิดพลาดได้โดยที่ไม่เคยยุ่ง ความกังวลหลักของฉันคือเมื่อคืนข้อผิดพลาดให้กับผู้ใช้

เป็นการดีที่จะใช้ข้อยกเว้นและโยน / จับข้อยกเว้นแทนที่จะส่งกลับ 0 หรือ 1 จากฟังก์ชันแล้วใช้ if / else เพื่อจัดการข้อผิดพลาด ดังนั้นทำให้ง่ายต่อการแจ้งผู้ใช้เกี่ยวกับปัญหา

ฉันมักจะหายไปจากข้อยกเว้น ครูสอนพิเศษ Java ของฉันที่มหาวิทยาลัยเมื่อหลายปีก่อนบอกฉันว่า "ข้อยกเว้นไม่ควรใช้ในรหัสการผลิตเป็นมากกว่าสำหรับการแก้ไขข้อบกพร่อง" ฉันรู้สึกว่าเขาโกหก

แต่ตัวอย่างฉันมีรหัสที่เพิ่มผู้ใช้ไปยังฐานข้อมูล ในระหว่างกระบวนการมากกว่า 1 สิ่งอาจผิดพลาดได้เช่นปัญหาฐานข้อมูลรายการซ้ำปัญหาเซิร์ฟเวอร์ ฯลฯ เมื่อเกิดปัญหาขึ้นระหว่างการลงทะเบียนผู้ใช้จำเป็นต้องรู้

เป็นวิธีที่ดีที่สุดในการจัดการข้อผิดพลาดใน PHP โปรดทราบว่าฉันใช้กรอบ MVC

คำตอบ:


14

เป็นการดีที่จะใช้ข้อยกเว้นและโยน / จับข้อยกเว้นแทนที่จะส่งกลับ 0 หรือ 1 จากฟังก์ชันแล้วใช้ if / else เพื่อจัดการข้อผิดพลาด ดังนั้นทำให้ง่ายต่อการแจ้งผู้ใช้เกี่ยวกับปัญหา

ไม่ไม่ไม่!

อย่าผสมข้อยกเว้นและข้อผิดพลาด ข้อยกเว้นคือดีพิเศษ ข้อผิดพลาดไม่ใช่ เมื่อคุณขอให้ผู้ใช้ป้อนจำนวนผลิตภัณฑ์และผู้ใช้ป้อน "hello" นั่นเป็นข้อผิดพลาด ไม่ใช่ข้อยกเว้น: ไม่มีอะไรพิเศษในการเห็นอินพุตที่ไม่ถูกต้องจากผู้ใช้ ทำไมคุณไม่สามารถใช้ข้อยกเว้นในกรณีที่ไม่ได้รับการยกเว้นได้เช่นเมื่อตรวจสอบความถูกต้องของอินพุต คนอื่นอธิบายแล้วและแสดงทางเลือกที่ถูกต้องสำหรับการตรวจสอบความถูกต้องของอินพุต

นอกจากนี้ยังหมายความว่าผู้ใช้ไม่สนใจเกี่ยวกับข้อยกเว้นและแสดงข้อยกเว้นเป็นทั้งที่ไม่เป็นมิตรและเป็นอันตราย ตัวอย่างเช่นข้อยกเว้นในระหว่างการดำเนินการของแบบสอบถาม SQL มักจะเปิดเผยตัวเองแบบสอบถาม คุณแน่ใจหรือไม่ว่าต้องการเสี่ยงที่จะแสดงข้อความดังกล่าวให้ทุกคนได้รับทราบ?

มีมากกว่า 1 สิ่งที่ผิดพลาดเช่นปัญหาฐานข้อมูลรายการซ้ำปัญหาเซิร์ฟเวอร์ ฯลฯ เมื่อเกิดปัญหาขึ้นระหว่างการลงทะเบียนผู้ใช้จำเป็นต้องรู้

ไม่ถูกต้อง. ในฐานะผู้ใช้ฉันไม่จำเป็นต้องรู้ปัญหาฐานข้อมูลรายการที่ซ้ำกัน ฯลฯ ฉันไม่สนใจปัญหาของคุณ สิ่งที่ฉันทำจำเป็นต้องรู้คือว่าฉันป้อนชื่อผู้ใช้ที่มีอยู่แล้ว ดังที่ได้กล่าวไปแล้วอินพุตที่ไม่ถูกต้องจากฉันต้องทริกเกอร์ข้อผิดพลาดไม่ใช่ข้อยกเว้น

วิธีการส่งออกข้อผิดพลาดเหล่านั้น มันขึ้นอยู่กับบริบท สำหรับชื่อผู้ใช้ที่ใช้ไปแล้วฉันต้องการเห็นธงสีแดงเล็ก ๆ ปรากฏขึ้นใกล้กับชื่อผู้ใช้ก่อนที่จะส่งแบบฟอร์มโดยบอกว่าชื่อผู้ใช้นั้นถูกใช้ไปแล้ว ไม่มี JavaScript จะต้องมีการตั้งค่าสถานะเดียวกันหลังจากการส่ง

ตัวอย่างของข้อผิดพลาดที่เปิดใช้งาน AJAX

สำหรับข้อผิดพลาดอื่น ๆ คุณจะแสดงแบบเต็มหน้าพร้อมกับข้อผิดพลาดหรือเลือกวิธีอื่นเพื่อแจ้งผู้ใช้ว่ามีบางอย่างผิดพลาด (เช่นข้อความที่จะปรากฏขึ้นจากนั้นจางหายไปที่ด้านบนของหน้า) คำถามนี้เกี่ยวข้องกับประสบการณ์ของผู้ใช้มากกว่าการตั้งโปรแกรม

จากมุมมองของโปรแกรมเมอร์ขึ้นอยู่กับชนิดของข้อผิดพลาดคุณจะเผยแพร่ในรูปแบบที่แตกต่างกัน ตัวอย่างเช่นในกรณีที่ชื่อผู้ใช้ไปแล้วคำขอ AJAX ที่http://example.com/?ajax=1&user-exists=Johnจะส่งคืนวัตถุ JSON ที่ระบุ:

  • ว่าผู้ใช้มีอยู่แล้ว
  • ข้อความแสดงข้อผิดพลาดเพื่อแสดงต่อผู้ใช้

จุดที่สองมีความสำคัญ: คุณต้องการให้แน่ใจว่าข้อความเดียวกันปรากฏขึ้นเมื่อส่งแบบฟอร์มโดยปิดการใช้งาน JavaScript และพิมพ์ชื่อผู้ใช้ซ้ำโดยเปิดใช้งาน JavaScript คุณไม่ต้องการทำซ้ำข้อความข้อผิดพลาดในซอร์สโค้ดฝั่งเซิร์ฟเวอร์และใน JavaScript!

นี่เป็นเทคนิคที่ใช้โดยเว็บไซต์ Stack Exhange ตัวอย่างเช่นถ้าฉันพยายามโหวตคำตอบของฉันเองการตอบกลับ AJAX มีข้อผิดพลาดที่จะแสดง:

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

คุณยังสามารถเลือกวิธีอื่นและตั้งค่าข้อผิดพลาดในหน้า HTML ก่อนกรอกแบบฟอร์ม ข้อดี: คุณไม่ต้องส่งข้อความแสดงข้อผิดพลาดในการตอบกลับ AJAX จุดด้อย: สิ่งที่เกี่ยวกับการเข้าถึง? ลองเรียกดูหน้าเว็บโดยไม่มี CSS และคุณจะเห็นข้อผิดพลาดที่เป็นไปได้ทั้งหมดปรากฏขึ้น


ฉันขอขอบคุณการตอบสนอง นี่คือสิ่งที่ฉันกำลังดิ้นรนอยู่ คุณมีแหล่งข้อมูลเกี่ยวกับข้อผิดพลาดในการรายงานโดยเฉพาะในแง่ของประสบการณ์ของผู้ใช้หรือไม่?
James Jeffery

อย่างที่ฉันบอกว่ามันขึ้นอยู่กับข้อผิดพลาดและการรายงานข้อผิดพลาดกับผู้ใช้นั้นเชื่อมโยงอย่างมากกับส่วนต่อประสานผู้ใช้ ฉันยังเน้นสองวิธีหลักในการรายงานข้อผิดพลาด: การรวมอย่างแน่นหนา (ค่าสถานะสีแดงที่เปิดใช้งาน AJAX ใกล้กับอินพุตด้วยค่าที่ไม่ถูกต้อง) และข้อผิดพลาดแบบเต็มหน้าซึ่งเป็นมิตรน้อยกว่า นี่ไม่ได้ตอบคำถามของคุณใช่ไหม
Arseni Mourzenko

2
+1 เพราะมันเป็นปัญหาประสบการณ์ผู้ใช้มากกว่าและไม่ใช่ปัญหาด้านเทคนิค
Charles Sprayberry

2
พล่าม, MainMa แค่พล่าม รหัสข้อผิดพลาดเป็น 80 และ 90 ข้อยกเว้นเป็นวิธีที่สะอาดกว่ามากในการจัดการกับสถานการณ์พิเศษเช่นการป้อนข้อมูลผิด (ตัวอย่างเช่น ValidationException) คุณไม่ได้ถูกบังคับให้แสดงข้อยกเว้นทุกอย่างแก่ผู้ใช้ ฉันเห็นคำตอบที่ดีกว่าของคุณ
เหยี่ยว

2
และในกรณีที่คุณไม่ทราบคุณสามารถควบคุมข้อยกเว้นที่คุณต้องการนำเสนอให้กับผู้ใช้และที่คุณไม่ต้องการนำเสนอ นั่นไม่ใช่ข้อโต้แย้งเลย
Falcon

13

เป็นการดีที่จะใช้ข้อยกเว้นและโยน / จับข้อยกเว้นแทนที่จะส่งกลับ 0 หรือ 1 จากฟังก์ชันแล้วใช้ if / else เพื่อจัดการข้อผิดพลาด ดังนั้นทำให้ง่ายต่อการแจ้งผู้ใช้เกี่ยวกับปัญหา

ใช่ใช่ใช่!

หากคุณต้องการมีรหัสที่สะอาดคุณควรใช้ข้อยกเว้นและไม่ต้องกังวลกับการใช้รหัสข้อผิดพลาด รหัสข้อผิดพลาดนั้นไม่มีความหมาย พวกเขามักจะเชื่อมโยงกับค่าคงที่ตัวเลขที่ไม่เปิดเผยข้อมูลมากนัก มันสามารถทำให้โค้ดของคุณอ่านไม่ได้และพวกมันจะทำให้ยากที่จะเผยแพร่ข้อมูลควบคู่ไปกับข้อผิดพลาด

อย่างไรก็ตามข้อยกเว้นเป็นคลาสและสามารถมีข้อมูลใด ๆ ที่คุณต้องการ ดังนั้นผู้ใช้ป้อนอินพุตผิดเช่น 'abc' สำหรับฟิลด์ตัวเลข ด้วยรหัสข้อผิดพลาดคุณจะไม่สามารถเผยแพร่ข้อมูลนี้ไปยังตัวจัดการข้อผิดพลาดโดยไม่ต้องเดือดปุด ๆ สิ่งที่ข้อยกเว้นให้ฟรี นอกจากนี้ข้อยกเว้นช่วยให้คุณมีค่าตอบแทนที่มีความหมายในฟังก์ชั่นและวิธีการในขณะที่ยังคงมีวิธีการที่จะล้มเหลวอย่างสวยงาม ยิ่งไปกว่านั้นข้อยกเว้นจะแพร่กระจายไปยังสถานที่ที่คุณต้องการจัดการ! ลองนึกภาพจำนวนสปาเก็ตตี้โค้ดที่คุณต้องใช้เพื่อเผยแพร่รหัสข้อผิดพลาดพร้อมข้อมูลที่มีความหมายไปยังตัวจัดการเลเยอร์หนึ่งหรือสองชั้นด้านบน

นอกจากนี้ข้อยกเว้นจะแสดงความหมายมากกว่ารหัสข้อผิดพลาดอย่างมาก Errorcodes นำไปสู่รหัสสปาเก็ตตี้ที่การจัดการข้อยกเว้นนำไปสู่การล้างรหัส

ยิ่งไปกว่านั้นมันง่ายที่จะลืมตรวจสอบรหัสสถานะ ในภาษาอย่าง Java คุณถูกบังคับให้ต้องจัดการกับข้อยกเว้น (บางอย่างที่คิดถึง C # เป็นต้น)

เป็นวิธีที่ดีที่สุดในการจัดการข้อผิดพลาดใน PHP โปรดทราบว่าฉันใช้กรอบ MVC

ใช้ข้อยกเว้นและจัดการกับมันในคอนโทรลเลอร์ของคุณ


ฉันเห็นด้วยมากกับคุณ !! ข้อยกเว้นที่ค่อนข้างสูงไม่บังคับใช้กับ PHP ในภาษาอื่น ๆ เป็นเรื่องดีที่รู้ว่าหลายคนกำลังรวมตัวกัน ...
David Conde

6
ฉันยอมรับว่าในกรณีส่วนใหญ่รหัสข้อผิดพลาดนั้นไม่มีความหมายพอสมควร อย่างไรก็ตามการโยนข้อยกเว้น Willy nilly นั้นแย่มาก! ควรสงวนข้อยกเว้นสำหรับกรณีพิเศษเท่านั้น ข้อยกเว้นทำให้โฟลว์ของโปรแกรมที่ไม่สามารถคาดเดาได้สามารถทำให้โค้ดยากที่จะติดตาม (และรักษาไว้) และใน PHP จะมีการปรับประสิทธิภาพที่ค่อนข้างสำคัญเมื่อเทียบกับ IF / THEN / ELSE ฉันมักจะชอบวิธีการที่จะกลับมาเป็นจริงเมื่อประสบความสำเร็จเป็นเท็จเมื่อล้มเหลวและมีเพียงข้อยกเว้นบางสิ่งที่ผิดพลาดอย่างมหันต์
GordonM

6

พิจารณาชั้นเรียนเล็ก ๆ ที่มีประโยชน์นี้:

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;            
    }

}

นั่นเป็นการใช้ข้อยกเว้นอย่างสมบูรณ์แบบ จากFunkyFile'sมุมมองไม่มีอะไรที่สามารถทำได้เพื่อแก้ไขคำนามหากเส้นทางไม่ถูกต้องหรือfile_get_contentsล้มเหลว สถานการณ์ที่ยอดเยี่ยมอย่างแท้จริง;)

แต่มีค่าสำหรับผู้ใช้ของคุณที่จะรู้ว่าคุณได้สะดุดกับเส้นทางของไฟล์ที่ไม่ถูกต้องที่ไหนสักแห่งในรหัสของคุณ? ตัวอย่างเช่น:

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!"; 
        }                           
    }        
}

นอกเหนือจากการบอกคนที่คุณกำลังมีวันที่แย่ตัวเลือกของคุณคือ:

  1. รั้งท้าย

    คุณมีวิธีรับข้อมูลอีกวิธีหนึ่งหรือไม่ ในตัวอย่างง่าย ๆ ของฉันข้างต้นดูเหมือนว่าจะไม่เกิดขึ้น แต่ให้พิจารณาสคีมาฐานข้อมูลหลัก / ทาส นายอาจจะล้มเหลวในการตอบโต้ แต่บางทีทาสก็ยังอยู่ที่นั่น (หรือกลับกัน)

  2. มันเป็นความผิดของผู้ใช้หรือไม่?

    ผู้ใช้ส่งข้อมูลผิดพลาดหรือไม่? บอกเธอเกี่ยวกับเรื่องนี้ คุณสามารถเห่าข้อความข้อผิดพลาดหรือจะดีและมาพร้อมกับข้อผิดพลาดที่มีรูปแบบเพื่อให้เธอสามารถพิมพ์ในเส้นทางที่ถูกต้อง

  3. มันเป็นความผิดของคุณเหรอ?

    และโดยคุณฉันหมายถึงทุกอย่างที่ไม่ใช่ผู้ใช้ดังนั้นตั้งแต่คุณพิมพ์เส้นทางของไฟล์ผิดไปจนถึงสิ่งที่ผิดปกติในเซิร์ฟเวอร์ของคุณ พูดอย่างเคร่งครัดถึงเวลาแล้วที่จะมีข้อผิดพลาด 503 HTTPเช่นกันบริการไม่พร้อมใช้งาน CI มีฟังก์ชั่นที่คุณสามารถสร้างshow_404()show_503()

คำแนะนำคุณควรคำนึงถึงข้อยกเว้นอันธพาล CodeIgniter เป็นโค้ดที่ยุ่งเหยิงและคุณไม่มีทางรู้ว่าข้อยกเว้นจะปรากฏขึ้นเมื่อใด ในทำนองเดียวกันคุณอาจลืมข้อยกเว้นของคุณเองและตัวเลือกที่ปลอดภัยที่สุดคือการใช้ตัวจัดการข้อยกเว้นทั้งหมด ใน PHP คุณสามารถทำได้ด้วย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");

และคุณยังสามารถดูแลข้อผิดพลาดโกงผ่านset_error_handler คุณสามารถเขียนตัวจัดการเดียวกันกับข้อยกเว้นหรือแปลงข้อผิดพลาดทั้งหมดเป็นErrorExceptionและให้ตัวจัดการข้อยกเว้นของคุณจัดการกับพวกเขา:

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");

นี่เป็นข้อมูลจริงๆไชโย!
James
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.