web-dev-qa-db-ja.com

PHPページのエラーを処理する最良の方法?

現在、私のページは次のようになっています。

if($_GET['something'] == 'somevalue')
{
    $output .= 'somecode';

    // make a DB query, fetch a row
    //...
    $row = $stmt->Fetch(PDO::ASSOC);

    if($row != null)
    {
        $output .= 'morecode';

        if(somethingIsOK())
        {
            $output .= 'yet more page output';
        }
        else
        {
            $error = 'something is most definitely not OK.';
        }
    }
    else
    {
        $error = 'the row does not exist.';
    }
}
else
{
    $error = 'something is not a valid value';
}

if($error == '') // no error
{
    //display $output on page
}
else // an error
{
    // display whatever error occurred on the page
}

私が物事を行っている方法は機能しますが、おそらく明白なことには非常に面倒で面倒です。コードの途中のどこかで関数を呼び出したり、変数の値を確認したり、DBクエリを確認したりするとします有効な結果が返されました。失敗した場合、エラーを出力しますか?別のif/elseブロックを作成し、すべてのコードを新しいifブロック内に移動する必要があります。これは賢いやり方のようには見えません。

私はtry/catchについて読んでいて、すべてのコードをtryステートメントの中に入れて、if/elseブロックなしでコードを順次実行させ、何かが失敗した場合に例外をスローすることを考えています。私が読んだことから、それは実行を停止し、それがキャッチブロックに直接ジャンプするようにします(ifステートメントがelseブロックに移動するのと同じように)、そこでエラーメッセージを出力できます。しかし、それは許容できる、または標準的な慣行ですか?

HTMLページを作成して出力するphpアプリケーションで、致命的かどうかにかかわらず、エラーを処理する最良の方法は何ですか?空白の画面で死ぬのではなく、それは非常にユーザーフレンドリーではないため、代わりにページの本文にメッセージを出力して、ヘッダーとフッターを表示できるようにします。

アドバイスありがとうございます!

36
Nate

これに対処する方法はたくさんありますが、率直に言って、本質的に「正しい」方法はありません。

あなたは自分で決める必要があります、どちらの方法があなたにとってより「快適」か-それは常に好みの問題です(あなたが避けなければならない特定のテクニックはありますが、それには正当な理由があります)。

ロジックの分割方法に大きく依存しますが、致命的でないエラーを返す可能性のあるすべてのコードを関数内に囲み、その関数の戻り値を使用してエラーがあったことを示します。

致命的なエラー の場合、例外を使用する傾向があります(_try-catch_ブロックを使用)。

明確にするために:

  • 致命的ではないエラーとは、recoverからエラーを回復できることです。つまり、何か問題が発生したとしても、実行して貴重な出力を生成できるコードがまだ残っています。たとえば、NTPプロトコルを使用して現在の時刻を取得したいが、サーバーが応答しない場合、ローカルのtime関数を使用しても、ユーザーにいくつかの貴重なデータを表示することができます。
  • 致命的なエラーとは、recoverからはできないエラーです。つまり、本当に悪いことが発生し、ページに何もできないことをユーザーに伝えることができる唯一のことです。と頼まれました。たとえば、データベースから一部のデータをフェッチしていて、_SQL Exception_を取得した場合、表示する価値のあるデータはなく、ユーザーに通知することしかできません。

致命的でないエラー(関数returnを使用)

致命的ではない問題に対処する方法として関数の戻り値を使用する良い例は、これが主な目的ではないときに、ページにあるファイルのコンテンツを表示しようとする関数です。ページの(たとえば、テキストファイルからフェッチされたバッジをすべてのページに表示する関数があります。これはかなりフェッチされていることはわかっていますが、私と一緒にください)。

_function getBadge($file){
    $f = fopen($file,'r');
    if(!$f){
        return null;
    }
    .. do some processing ..
    return $badges;
}

$badges = getBadges('badges.txt');
if(!$badges){
    echo "Cannot display badges.";
} else {
    echo $badges;
}
.. carry on doing whatever page should be doing ..
_

実際、関数fopen自体がこの例です- それは を返します。

成功した場合はファイルポインタリソース、エラーの場合はFALSEを返します。


致命的エラー(例外を使用-try-catch)

実行する必要があるコードがある場合それはユーザーが望んでいたとおりであるため(たとえば、データベースからすべてのニュースを読み取り、それらをユーザー)、例外を使用できます。簡単な例を考えてみましょう。ユーザーが自分のプロファイルにアクセスして、取得したすべてのメッセージを確認したいと考えました(今のところ、メッセージはプレーンテキストで格納されていると仮定しましょう)。あなたは次のような機能を持っているかもしれません:

_function getMessages($user){
    $messages = array();
    $f = fopen("messages_$user.txt","r");
    if(!$f){
        throw new Exception("Could not read messages!");
    }
    ... do some processing ...
    return $messages;
}
_

次のように使用します。

_try{
    ..do some stuff..
    $messages = getMessages($_SESSION['user'])); //assuming you store username in $_SESSION
    foreach($messages as $msg){
        echo $msg."<br/>";
    }
} catch(Exception $e){
    echo "Sorry, there was an error: ".$e->getMessage();
}
_

これは、他のすべてのコードを実行する「トップレベル」のスクリプトがある場合に便利です。つまり、たとえば、_index.php_では、次のようになります。

_try{
    .. execute some code, perform some functions ..
} catch(Exception $e){
    echo "Sorry, there was an error: ".$e->getMessage();
}
_

例外を使いすぎないでください。

何をするにしても、回復できるものをチェックする方法として例外を使用しないでください。別の質問で を読んでください (完全なクレジットはAnton Gogolevに非常に良い説明と他の回答が表示されます- ers)これが事実である理由について。

参考文献

さて、エラーに対処する方法を学ぶには、いくつかのことを試してみて、自分にとって何が良いかを見るより良い方法はありません。以下が役に立つかもしれません:

お役に立てれば :)

35
Bart Platak

PHPには組み込みのクラス ErrorException があり、 PHPエラー を例外に変換します。これを処理しないと、当然実行が停止します。

例外により、エラー処理メカニズム(catchを試す)とデバッグ情報(スタックトレース)が改善されました。

これを実行パスの最上部(構成、またはすべてのコードに最初に含まれるもの)に含めます。

_ set_error_handler(function($nNumber, $strMessage, $strFilePath, $nLineNumber){
      throw new \ErrorException($strMessage, 0, $nNumber, $strFilePath, $nLineNumber);
 }, /*E_ALL*/ -1);
_

PDOは例外のスローをサポートしていますが、デフォルトではオフになっているため、有効にする必要があります。

_ $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
_

MySQLを使用している場合は、必須フィールドを設定していない場合のエラーと、デフォルトで許可されている他の多くのエラー/警告も必要です。

_ $pdo->exec("SET sql_mode = 'STRICT_ALL_TABLES'");
_

例外は、他の多くのプログラミング言語と同様に 最後にcatchを試す を使用して処理できます。

_try
{
    echo $iAmAnUndefinedVariable;
}
catch(\Throwable $exception)
{
    /*[...]*/
}
_

ものを検証するときは、例外をスローするだけです:throw new Exception("Missing URL variable userId!");

PHPがレガシー エラー報告 のことからいつかきれいな休憩を取り、デフォルトで例外をスローするのはいいことです(error_reporting()を廃止し、デフォルトを変更してください)。

6

これははるかにエレガントで読みやすいです。

try
{

    if($_GET['something'] != 'somevalue') 
    {
        throw new Exception ('something is not a valid value');
    }


    $output .= 'somecode';

    // make a DB query, fetch a row
    //...
    $row = $stmt->Fetch(PDO::ASSOC);

    if($row == null)
    {
        throw new Exception ('the row does not exist.');
    }


    $output .= 'morecode';


    if(somethingIsOK())
    {
        $output .= 'yet more page output';
    }
    else
    {
        throw new Exception ('something is most definitely not OK.');
    }


    echo $output;

}
catch (Exception $e)
{
    echo $e->getMessage();
}
5
Edson Medina

try-catchの使用は、使用できる最もクリーンなソリューションの1つです。

try-catch形式に変換されたコードを使用して、エラーが発生した場合でもヘッダーとフッターを表示する例を作成しました。

PHP:

<?php
try {
    $output = array();
    if($_GET['something'] != 'somevalue') throw new Exception('something does not have a valid value.');
    $output[] = 'Some Code';
    $row = mt_Rand(0, 10) < 5 ? null : mt_Rand(0, 100);
    if($row === null) throw new Exception('The row does not exist.');
    $output[] = $row;
    if(!somethingIsOK()) throw new Exception('Something is most definitely not OK.');
    $output[] = 'Yet more page output';
} catch(Exception $e) {
    $output[] = 'Error: ' . $e->getMessage(); // To show output and error
    $output = array('Error: ' . $e->getMessage()); // To only show error
}
function somethingIsOK() {
    return mt_Rand(0, 10) < 5;
}
?>

HTML:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8" />
    <title>PHP Error test</title>
    <style type="text/css">
body {
    background: #eee;
    text-align: center
}
#content {
    padding: 60px
}
#header {
    padding: 30px;
    background: #fff
}
#footer {
    padding: 10px;
    background: #ddd
}
    </style>
</head>
<body>
    <div id="header">Header</div>
    <div id="content">
<?php echo implode('<br />', $output); ?>

    </div>
    <div id="footer">Footer</div>
</body>
</html>

参照:

2
uınbɐɥs

クエリのPDOエラー例外処理。実際にはすべてのコードを実行する必要があります。

try{

}

catch{


}

finally{

}

この理由は、長いスクリプトでエラーが発生している場所を大まかに特定できると、デバッグがはるかに簡単になるためです。

詳細はこちら: http://php.net/manual/en/language.exceptions.php

1
CodeTalk

エラーハンドラー(set_error_handler)を作成し、その中に例外をスローします。
例外をサポートしない関数に役立ちます。

0
Dmitry

エラー処理関数を使用して、PHPエラーと警告を正しく処理します(例 こちら を参照)

PHP=でのエラー処理の最良の方法は、phpファイルの先頭にこの行を追加することで、すべてのエラー報告を停止できます-

error_reporting(0);

//OR

error_reporting('E_ALL');

// Predefined Constant

PHP関数を使用してエラーを処理:

  • debug_backtrace —バックトレースを生成する
  • debug_print_backtrace —バックトレースを出力する
  • error_clear_last —最新のエラーをクリアする
  • error_get_last —最後に発生したエラーを取得する
  • error_log —定義されたエラー処理ルーチンにエラーメッセージを送信する
  • error_reporting —どのPHPエラーが報告されるかを設定します
  • restore_error_handler —以前のエラーハンドラ関数を復元する
  • restore_exception_handler —以前に定義された例外ハンドラー関数を復元する
  • set_error_handler —ユーザー定義のエラーハンドラ関数を設定する
  • set_exception_handler —ユーザー定義の例外ハンドラ関数を設定する
  • trigger_error —ユーザーレベルのエラー/警告/通知メッセージを生成します
  • user_error — trigger_errorのエイリアス

上記のすべての関数は、PHPのエラー処理に使用されます。

0
Steve