MVC使用時のPHPでのエラー処理


12

私は最近Codeigniterを頻繁に使用していますが、気になるのはエラーを処理してユーザーに表示することです。乱雑になることなくエラーを処理するのが得意ではありませんでした。私の主な関心事は、ユーザーにエラーを返すときです。

関数から0または1を返し、if / elseを使用してエラーを処理するのではなく、例外と例外をスロー/キャッチすることをお勧めします。したがって、問題についてユーザーに簡単に通知できます。

私は例外から離れる傾向があります。数年前、大学の私のJava講師は「例外はプロダクションコードで使用すべきではありません。デバッグ用ではありません」と言っていました。私は彼が嘘をついていると感じました。

しかし、例として、ユーザーをデータベースに追加するコードがあります。プロセス中に、データベースの問題、重複エントリ、サーバーの問題など、2つ以上の問題が発生する可能性があります。登録中に問題が発生した場合、ユーザーはそれについて知る必要があります。

MVCフレームワークを使用していることを念頭に置いて、PHPでエラーを処理する最良の方法は何ですか。

回答:


14

関数から0または1を返し、if / elseを使用してエラーを処理するのではなく、例外と例外をスロー/キャッチすることをお勧めします。したがって、問題についてユーザーに簡単に通知できます。

ダメダメダメ!

例外とエラーを混在させないでください。例外は、まあ、例外的です。エラーはありません。ユーザーに製品の数量を入力するように依頼し、ユーザーが「hello」と入力すると、エラーになります。例外ではありません。ユーザーからの無効な入力を見るのに例外はありません。入力を検証するときなど、例外的でない場合に例外を使用できないのはなぜですか?他の人々はすでにそれを説明し、入力検証のための有効な代替手段を示しました。

これはまた、ユーザーがあなたの例外を気にしないことを意味します、そして、例外示すことは友好的でなく危険です。たとえば、SQLクエリの実行中に例外が発生すると、クエリ自体が明らかになることがよくあります。みんなにそのようなメッセージを見せるためにリスクを取ってよろしいですか?

データベースの問題、重複エントリ、サーバーの問題など、複数の問題が発生する可能性があります。登録中に問題が発生した場合、ユーザーはそのことを知る必要があります。

違う。ユーザーとして、私はあなたのデータベースの問題、重複したエントリなどを知る必要はありません。あなたの問題を本当に気にしません。私はやる知っている必要があり、私はすでに存在しているユーザー名を入力したことです。すでに述べたように、私からの間違った入力は例外ではなくエラーを引き起こさなければなりません。

これらのエラーを出力する方法は?コンテキストに依存します。すでに使用されているユーザー名については、フォームを送信する前に、ユーザー名が既に使用されていることを示す小さな赤い旗がユーザー名の近くに表示されることを確認します。JavaScriptを使用しない場合、送信後に同じフラグを表示する必要があります。

AJAX対応エラーの例

その他のエラーについては、エラーのあるページ全体を表示するか、何か問題が発生したことをユーザーに通知する別の方法を選択します(たとえば、メッセージが表示され、ページの上部で消えます)。質問は、プログラミングよりもユーザーエクスペリエンスに関連しています。

プログラマーの観点からは、エラーの種類に応じて、さまざまな方法でエラーを伝播します。たとえば、ユーザー名がすでに取得されている場合、AJAXリクエストは次をhttp://example.com/?ajax=1&user-exists=John示すJSONオブジェクトを返します:

  • ユーザーが既に存在すること、
  • ユーザーに表示するエラーメッセージ。

2番目のポイントは重要です。JavaScriptを無効にしてフォームを送信するときと、JavaScriptを有効にして重複するユーザー名を入力するときの両方で同じメッセージが表示されるようにする必要があります。サーバー側のソースコードとJavaScriptでエラーメッセージのテキストを複製したくない!

これは、実際にはStack Exhange Webサイトで使用されている手法です。たとえば、自分の回答に投票しようとすると、AJAX応答には表示するエラーが含まれます。

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

別の方法を選択し、フォームに入力する前にHTMLページでエラーを事前設定することもできます。長所:AJAX応答でエラーメッセージを送信する必要はありません。短所:アクセシビリティはどうですか?CSSなしでページを閲覧しようとすると、考えられるすべてのエラーが表示されます。


応答に感謝します。これはまさに私が苦労していることです。特にユーザーエクスペリエンスに関して、エラーの報告に関するリソースはありますか?
ジェームズジェフリー

さて、私が言ったように、それは本当にエラーに依存し、ユーザーへのエラーの報告はユーザーインターフェースに強くリンクされています。また、エラーを報告する2つの主な方法を強調しました:緊密な統合(間違った値を持つ入力の近くのAJAX対応の赤旗)と、より深刻な場合に使用される、はるかに友好的でない全ページエラー。これはあなたの質問に答えませんか?
アルセニムルゼンコ

2
+1は技術的な問題ではなく、ユーザーエクスペリエンスの問題であるため
チャールズスプレーベリー

2
でたらめ、MainMa。ただでたらめ。エラーコードは80年代と90年代です。例外は、間違った入力(ValidationExceptionなど)のような特別な状況を処理するためのはるかにクリーンな方法です。ユーザーにすべての例外を表示する必要はありません。あなたのより良い答えを見てきました。
ファルコン

2
そして、あなたがそれを知らなかった場合のために:どの例外をユーザーに提示したいか、そしてどの例外を提示したくないかを制御することができます。したがって、それは実際にはまったく議論ではありません。
ファルコン

13

関数から0または1を返し、if / elseを使用してエラーを処理するのではなく、例外と例外をスロー/キャッチすることをお勧めします。したがって、問題についてユーザーに簡単に通知できます。

はいはいはい!

きれいなコードが必要な場合は、例外をほぼ排他的に使用し、エラーコードを使用しないでください。エラーコードは無意味です。それらはほとんどの場合、多くの情報を明らかにしない数値定数に結びついています。コードが読めなくなる可能性があり、エラーと一緒にデータを伝播するのが難しくなります。

ただし、例外はクラスであり、任意の情報を含めることができます。そのため、ユーザーは数字フィールドに「abc」のような間違った入力を入力しました。エラーコードを使用すると、大量のバブルなしでは、この情報をエラーのハンドラーに伝達することはできません。例外が無料で提供するもの。また、例外を使用すると、エレガントに失敗する方法を残しながら、関数やメソッドに意味のある戻り値を含めることができます。さらに良いことに、例外は処理したい場所に直接伝播されます!意味のあるデータを含むエラーコードを1つまたは2つ上のレイヤーのハンドラーに伝達するために必要なスパゲッティコードの量を想像してください。

また、例外はエラーコードよりもはるかに意味的に表現します。エラーコードはスパゲッティコードにつながり、例外処理はクリーンなコードにつながります。

さらに、ステータスコードの確認を忘れがちです。Javaのような言語では、例外(たとえば、C#がミスするもの)を処理する必要があります。

MVCフレームワークを使用していることを念頭に置いて、PHPでエラーを処理する最良の方法は何ですか。

例外を使用して、コントローラーでそれらを処理します。


私はあなたにとても同意します!! 他の言語のように強制nはPHPなどの例外Altough、...多くの人々がそれらをincorpratingしていることを知っているのは良いですではありません
デビッド・コンデ

6
ほとんどの場合、エラーコードはほとんど意味がないことに同意します。ただし、例外を意図的にスローすることは非常に悪いです!例外は例外的な状況にのみ予約する必要があります。例外は予測不可能なプログラムフローを引き起こし、コードを追跡するのを難しくする(したがって、維持する)可能性があり、PHPではIF / THEN / ELSEと比較してかなり重大なパフォーマンスの低下をもたらします。私は、成功した場合にtrue、失敗した場合にfalseを返すメソッドを好む傾向があります。
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");

これは本当に有益でした!
ジェームズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.