36

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

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ブロックなしでコードを順番に実行し、何かが失敗した場合は例外をスローすることを考えていました. 私が読んだことから、それは実行を停止し、catch ブロックに直接ジャンプし (失敗した if ステートメントが else ブロックに移動するのと同じように)、そこでエラー メッセージを出力できます。しかし、それは受け入れられる、または標準的な慣行ですか?

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

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

4

8 に答える 8

36

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

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

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

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

明確にするために:

  • 致命的ではないエラーとは、回復可能なエラーです。つまり、何か問題が発生したとしても、実行して価値のある出力を生成できるコードが残っていることを意味します。たとえば、NTPプロトコルを使用して現在の時刻を取得したいが、サーバーが応答しなかった場合、ローカルtime関数を使用することを決定して、ユーザーに貴重なデータを表示することができます。
  • 致命的なエラーとは、回復できないエラーです。つまり、何か本当に悪いことが起こり、ページが要求されたことを実行できないことをユーザーに伝えることしかできません。たとえば、データベースからデータを取得して得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 を返します。


Fatal-Errors (例外を使用 - 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に完全なクレジットがあります)。

参考文献

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

お役に立てれば :)

于 2012-08-12T03:09:41.150 に答える
6

PHPには、PHPエラーを例外に変換するための組み込みクラスErrorExceptionがあります。例外は、処理されない場合、自然に実行を停止します。

例外により、エラー処理メカニズム(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'");

例外は、 trycatchfinallyを使用して他の多くのプログラミング言語と同じように処理できます。

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

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

PHPがいつか従来のエラー報告を完全に中断し、デフォルトで例外をスローする(error_reporting()を廃止し、デフォルトを変更する)と便利です。

于 2012-08-13T15:00:03.217 に答える
5

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

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();
}
于 2012-08-14T09:42:36.090 に答える
3

Usingtry-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>

参考文献:

于 2012-08-13T00:39:07.180 に答える
1

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

try{

}

catch{


}

finally{

}

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

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

于 2012-08-12T03:17:37.223 に答える
0

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

于 2012-08-19T01:27:02.527 に答える
0

エラー処理関数を使用して、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 のエラー処理に使用されます。

于 2015-11-27T06:11:09.850 に答える
-3

見栄えがよく、機能するコード構造を探している場合は、whitelist私がいつも使用している方法を使用できます。$_GET例-変数の検証:

$error = false;

if(!isset($_GET['var'])) 
{
    $error = 'Please enter var\'s value';
}
elseif(empty($_GET['var'])) 
{
    $error = 'Var shouldn\'t be empty';
}
elseif(!ctype_alnum($_GET['var'])) 
{
    $error = 'Var should be alphanumeric';
}

//if we have no errors -> proceed to db part
if(!$error) 
{
    //inserting var into database table
}

だから、これはそれです、if/elseifネストせずに、たった2ブロックです

于 2012-08-17T00:35:30.573 に答える