Xử lý lỗi trong PHP khi sử dụng MVC


12

Gần đây tôi đã sử dụng Codeigniter rất nhiều, nhưng có một điều khiến tôi lo lắng là xử lý lỗi và hiển thị chúng cho người dùng. Tôi chưa bao giờ giỏi xử lý lỗi mà không bị lộn xộn. Mối quan tâm chính của tôi là khi trả lại lỗi cho người dùng.

Có phải là cách thực hành tốt để sử dụng ngoại lệ và ném / bắt ngoại lệ thay vì trả về 0 hoặc 1 từ các hàm và sau đó sử dụng if / other để xử lý lỗi. Do đó, làm cho nó dễ dàng hơn để thông báo cho người dùng về vấn đề này.

Tôi có xu hướng đi xa khỏi ngoại lệ. Gia sư Java của tôi tại trường đại học vài năm trước đã nói với tôi "không nên sử dụng ngoại lệ trong mã sản xuất để sửa lỗi nhiều hơn". Tôi có cảm giác anh đang nói dối.

Nhưng, một ví dụ, tôi có mã thêm người dùng vào cơ sở dữ liệu. Trong quá trình, có hơn 1 điều có thể xảy ra, chẳng hạn như sự cố cơ sở dữ liệu, mục trùng lặp, sự cố máy chủ, v.v. Khi xảy ra sự cố trong quá trình đăng ký, người dùng cần biết về nó.

Cách tốt nhất để xử lý lỗi trong PHP, hãy nhớ rằng tôi đang sử dụng khung MVC.

Câu trả lời:


14

Có phải là cách thực hành tốt để sử dụng ngoại lệ và ném / bắt ngoại lệ thay vì trả về 0 hoặc 1 từ các hàm và sau đó sử dụng if / other để xử lý lỗi. Do đó, làm cho nó dễ dàng hơn để thông báo cho người dùng về vấn đề này.

Không không không!

Đừng trộn lẫn các ngoại lệ và lỗi. Ngoại lệ là, tốt, đặc biệt. Lỗi thì không. Khi bạn yêu cầu người dùng nhập số lượng sản phẩm và người dùng nhập "xin chào", đó là một lỗi. Đó không phải là một ngoại lệ: không có gì đặc biệt khi thấy đầu vào không hợp lệ từ người dùng. Tại sao bạn không thể sử dụng ngoại lệ trong các trường hợp không đặc biệt, như khi xác thực đầu vào? Những người khác đã giải thích nó rồi, và hiển thị một sự thay thế hợp lệ cho xác nhận đầu vào.

Điều này cũng có nghĩa là người dùng không quan tâm đến các ngoại lệ của bạn và hiển thị các ngoại lệ vừa không thân thiện vừa nguy hiểm . Ví dụ: một ngoại lệ trong khi thực hiện truy vấn SQL thường tiết lộ chính truy vấn đó. Bạn có chắc chắn muốn mạo hiểm để hiển thị thông điệp như vậy cho mọi người?

nhiều hơn một điều có thể sai, chẳng hạn như vấn đề cơ sở dữ liệu, mục trùng lặp, sự cố máy chủ, v.v. Khi xảy ra sự cố trong quá trình đăng ký, người dùng cần biết về nó.

Sai lầm. Là người dùng, tôi không cần biết các vấn đề về cơ sở dữ liệu, các mục trùng lặp, v.v. Tôi thực sự không quan tâm đến các vấn đề của bạn . Những gì tôi làm cần phải biết là tôi bước vào một tên người dùng đó đã tồn tại. Như đã nói, một đầu vào sai từ tôi phải gây ra lỗi, không phải là ngoại lệ.

Làm thế nào để xuất ra những lỗi đó? Nó phụ thuộc vào ngữ cảnh. Đối với tên người dùng đã được sử dụng, tôi muốn thấy một lá cờ nhỏ màu đỏ xuất hiện gần tên người dùng, thậm chí trước khi gửi biểu mẫu, nói rằng tên người dùng đã được sử dụng. Không có JavaScript, cùng một cờ phải xuất hiện sau khi gửi.

Một ví dụ về lỗi kích hoạt AJAX

Đối với các lỗi khác, bạn sẽ hiển thị toàn bộ trang có lỗi hoặc chọn một cách khác để thông báo cho người dùng rằng có lỗi xảy ra (ví dụ: một thông báo sẽ xuất hiện, sau đó mờ dần ở đầu trang). Câu hỏi sau đó liên quan nhiều đến trải nghiệm người dùng hơn là lập trình.

Từ quan điểm lập trình viên, tùy thuộc vào loại lỗi, bạn sẽ tuyên truyền nó theo những cách khác nhau. Ví dụ: trong trường hợp tên người dùng đã được sử dụng, yêu cầu AJAX http://example.com/?ajax=1&user-exists=Johnsẽ trả về một đối tượng JSON cho biết:

  • Người dùng đã tồn tại,
  • Thông báo lỗi hiển thị cho người dùng.

Điểm thứ hai rất quan trọng: bạn muốn chắc chắn rằng cùng một thông báo xuất hiện cả khi gửi biểu mẫu với JavaScript bị vô hiệu hóa và nhập tên người dùng trùng lặp với JavaScript được bật. Bạn không muốn sao chép văn bản của thông báo lỗi trong mã nguồn phía máy chủ và bằng JavaScript!

Đây thực sự là kỹ thuật được sử dụng bởi các trang web Stack Exhange. Ví dụ: nếu tôi cố gắng nâng cao câu trả lời của riêng mình, phản hồi AJAX chứa lỗi hiển thị:

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

Bạn cũng có thể chọn một cách tiếp cận khác và đặt trước các lỗi trong trang HTML trước khi biểu mẫu được điền. Ưu điểm: bạn không phải gửi thông báo lỗi trong phản hồi AJAX. Nhược điểm: những gì về khả năng tiếp cận? Hãy thử duyệt trang mà không có CSS ​​và bạn sẽ thấy tất cả các lỗi có thể xuất hiện.


Tôi đánh giá cao phản ứng. Đây chính xác là những gì tôi đang đấu tranh với. Bạn có tài nguyên nào về báo cáo lỗi, đặc biệt là về trải nghiệm người dùng không?
James Jeffery

Vâng, như tôi đã nói, nó thực sự phụ thuộc vào lỗi và việc báo cáo lỗi cho người dùng được liên kết chặt chẽ với giao diện người dùng. Tôi cũng nhấn mạnh hai cách chính để báo cáo lỗi: tích hợp chặt chẽ (cờ đỏ kích hoạt AJAX gần đầu vào với giá trị sai) và lỗi toàn trang, ít thân thiện hơn, được sử dụng cho các trường hợp nghiêm trọng hơn. Điều này không trả lời câu hỏi của bạn?
Arseni Mourzenko

2
+1 vì đây là vấn đề về trải nghiệm người dùng nhiều hơn và không phải là vấn đề kỹ thuật
Charles Sprayberry

2
Nhảm nhí, MainMa. Nhảm nhí. Mã lỗi là những năm 80 và 90. Các ngoại lệ là một cách rõ ràng hơn nhiều để xử lý các trường hợp đặc biệt như nhập sai (ví dụ: ValidationException). Bạn không bị buộc phải hiển thị mọi ngoại lệ cho người dùng. Tôi đã thấy câu trả lời tốt hơn của bạn.
Falcon

2
Và chỉ trong trường hợp bạn không biết điều đó: Bạn có thể kiểm soát những ngoại lệ nào bạn muốn trình bày cho người dùng và những gì bạn không muốn trình bày. Vì vậy, đó thực sự không phải là một cuộc tranh luận.
Falcon

13

Có phải là cách thực hành tốt để sử dụng ngoại lệ và ném / bắt ngoại lệ thay vì trả về 0 hoặc 1 từ các hàm và sau đó sử dụng if / other để xử lý lỗi. Do đó, làm cho nó dễ dàng hơn để thông báo cho người dùng về vấn đề này.

Có có có!

Nếu bạn muốn có mã sạch, bạn hầu như chỉ nên sử dụng ngoại lệ và không bận tâm sử dụng mã lỗi. Mã lỗi là vô nghĩa. Chúng hầu như luôn được gắn với một số hằng số không tiết lộ nhiều thông tin. Nó có thể làm cho mã của bạn không thể đọc được và chúng sẽ khiến cho việc truyền dữ liệu cùng với lỗi trở nên khó khăn.

Tuy nhiên, ngoại lệ là các lớp và có thể chứa bất kỳ thông tin nào bạn muốn. Vì vậy, người dùng đã nhập sai, như 'abc' cho trường số. Với mã lỗi, bạn sẽ không thể truyền thông tin này đến người xử lý lỗi mà không có nhiều bong bóng. Một cái gì đó ngoại lệ cung cấp miễn phí. Ngoài ra, các ngoại lệ cho phép bạn có các giá trị trả về có ý nghĩa trong các hàm và phương thức trong khi vẫn có cách để thất bại một cách thanh lịch. Thậm chí tốt hơn, Ngoại lệ được truyền bá ngay đến nơi bạn muốn xử lý chúng! Hãy tưởng tượng số lượng mã spaghetti bạn sẽ cần truyền mã lỗi với dữ liệu có ý nghĩa đến một trình xử lý một hoặc hai lớp ở trên.

Ngoài ra, các ngoại lệ thể hiện rất nhiều về mặt ngữ nghĩa so với mã lỗi. Mã lỗi dẫn đến mã spaghetti trong đó xử lý ngoại lệ dẫn đến mã sạch.

Hơn nữa, thật dễ dàng để quên kiểm tra mã trạng thái. Trong các ngôn ngữ như Java, bạn buộc phải xử lý các trường hợp ngoại lệ (ví dụ như C # bỏ lỡ).

Cách tốt nhất để xử lý lỗi trong PHP, hãy nhớ rằng tôi đang sử dụng khung MVC.

Sử dụng ngoại lệ và xử lý chúng trong bộ điều khiển của bạn.


Tôi rất đồng ý với bạn !! Các ngoại lệ rõ ràng không được thi hành như PHP như trong các ngôn ngữ khác, thật tốt khi biết rằng nhiều người đang kết hợp chúng ...
David Conde

6
Tôi đồng ý rằng trong hầu hết các trường hợp, mã lỗi là khá vô nghĩa. Tuy nhiên, ném ngoại lệ willy nilly là cực kỳ xấu! Trường hợp ngoại lệ chỉ được dành riêng cho trường hợp đặc biệt. Các ngoại lệ gây ra luồng chương trình không thể đoán trước, có thể khiến mã khó theo dõi (và do đó duy trì) và trong PHP, chúng mang một hình phạt hiệu suất khá đáng kể so với IF / THEN / ELSE. Tôi có xu hướng thích các phương pháp để trả lại sự thật khi thành công, sai khi thất bại và chỉ đưa ra một ngoại lệ của một cái gì đó cực kỳ sai lầm.
GordonM

6

Hãy xem xét lớp học nhỏ tiện dụng này:

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

}

Đó là một cách sử dụng ngoại lệ hoàn toàn tốt. Từ FunkyFile'squan điểm, hoàn toàn không có gì có thể được thực hiện để khắc phục tình trạng bão hòa nếu đường dẫn không hợp lệ hoặc file_get_contentsthất bại. Một tình huống thực sự đặc biệt;)

Nhưng có bất kỳ giá trị nào để người dùng của bạn biết rằng bạn đã vấp phải một đường dẫn tệp sai, ở đâu đó trong mã của bạn không? Ví dụ:

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

Khác với việc nói với mọi người rằng bạn đang có một ngày tồi tệ, các lựa chọn của bạn là:

  1. Dự phòng

    Bạn có cách nào khác để lấy thông tin không? Trong ví dụ đơn giản của tôi ở trên, có vẻ như không có khả năng, nhưng hãy xem xét một lược đồ cơ sở dữ liệu chủ / nô lệ. Người chủ có thể đã không trả lời nhưng có lẽ, chỉ có thể, nô lệ vẫn ở ngoài đó (hoặc ngược lại).

  2. Có phải lỗi của người dùng không?

    Người dùng đã gửi đầu vào bị lỗi? Vâng, nói với cô ấy về nó. Bạn có thể sủa một thông báo lỗi, hoặc tốt đẹp và kèm theo thông báo lỗi đó với một biểu mẫu để cô ấy có thể nhập đúng đường dẫn.

  3. Có phải lỗi của bạn không?

    Và theo bạn, ý tôi là bất cứ điều gì không phải là người dùng, do đó, từ việc bạn nhập một đường dẫn tệp sai, đến một cái gì đó không ổn trong máy chủ của bạn. Nói một cách chính xác, đã đến lúc xảy ra lỗi 503 HTTP , vì vậy, dịch vụ không khả dụng. CI có show_404()chức năng, bạn có thể dễ dàng xây dựng show_503().

Lời khuyên, bạn nên xem xét các trường hợp ngoại lệ giả mạo. CodeIgniter là một đoạn mã lộn xộn và bạn không bao giờ biết khi nào một ngoại lệ sẽ xuất hiện. Tương tự, bạn có thể quên đi các ngoại lệ của riêng mình và tùy chọn an toàn nhất là triển khai một trình xử lý ngoại lệ. Trong PHP bạn có thể làm điều đó với 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");

Và bạn cũng có thể xử lý các lỗi giả mạo, thông qua set_error_handler . Bạn có thể viết trình xử lý tương tự như ngoại lệ hoặc chuyển đổi tất cả các lỗi sang ErrorExceptionvà để trình xử lý ngoại lệ của bạn xử lý chúng:

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

Đây thực sự là thông tin, chúc mừng!
James
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.