私はいくつかの基本に精通していますが、もっと知りたいのは、PHP、特にライブサイトやWebアプリでエラー処理(例外のスローを含む)をいつ、なぜ使用する必要があるかです。それは使いすぎの可能性があるものですか?もしそうなら、使いすぎはどのように見えますか?使用してはいけない場合はありますか?また、エラー処理に関する一般的なセキュリティ上の懸念事項は何ですか?
10 に答える
すでに述べたことに加えて、Web アプリケーションのエラーをログに記録することが最も重要であるということです。こうすれば、Jeff "Coding Horror" Atwood が示唆するように、ユーザーがアプリで問題を経験したときに (「何が問題なのか」を尋ねるのではなく) 知ることができます。
これを行うには、次のタイプのインフラストラクチャをお勧めします。
- データベースに「クラッシュ」テーブルを作成し、エラーを報告するための一連のラッパー クラスを作成します。クラッシュのカテゴリを設定することをお勧めします (「ブロッキング」、「セキュリティ」、「PHP エラー/警告」(vs 例外) など)。
- すべてのエラー処理コードで、必ずエラーを記録してください。これを一貫して実行するかどうかは、API をどれだけうまく構築したか (上記の手順) に依存します。適切に実行すれば、クラッシュを記録するのは簡単です。
余分なクレジット: クラッシュがデータベース レベルのクラッシュになる場合があります: DB サーバーのダウンなど。 DBに書き込みます)。その場合、Crash ラッパー クラスのフェイルオーバー ロジックを次のいずれかに記述します。
- 管理者に電子メールを送信する、AND/OR
- クラッシュの詳細をプレーン テキスト ファイルに記録する
これはすべてやり過ぎのように聞こえますが、私を信じてください。これにより、アプリケーションが「安定」または「不安定」として受け入れられるかどうかが異なります。その違いは、すべてのアプリが常に不安定またはクラッシュする状態で開始されるという事実から生じますが、アプリのすべての問題を知っている開発者は、実際にそれを修正するチャンスがあります。
大まかに言えば、エラーはPHPのレガシーですが、例外はエラーを処理するための最新の方法です。その場合、最も簡単なことは、例外をスローするエラーハンドラーを設定することです。このようにして、すべてのエラーが例外に変換され、1つのエラー処理スキームを処理するだけで済みます。次のコードは、エラーを例外に変換します。
function exceptions_error_handler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
set_error_handler('exceptions_error_handler');
error_reporting(E_ALL ^ E_STRICT);
ただし、コードがエラーを処理するように特別に設計されている場合がいくつかあります。たとえば、ドキュメントを検証するときに警告を発するschemaValidate
メソッド。DomDocument
エラーを例外に変換すると、最初の失敗後に検証が停止します。これが必要な場合もありますが、ドキュメントを検証するときに、実際にはすべての失敗が必要になる場合があります。この場合、エラーを収集するエラーハンドラを一時的にインストールできます。これがその目的のために使用した小さなスニペットです。
class errorhandler_LoggingCaller {
protected $errors = array();
function call($callback, $arguments = array()) {
set_error_handler(array($this, "onError"));
$orig_error_reporting = error_reporting(E_ALL);
try {
$result = call_user_func_array($callback, $arguments);
} catch (Exception $ex) {
restore_error_handler();
error_reporting($orig_error_reporting);
throw $ex;
}
restore_error_handler();
error_reporting($orig_error_reporting);
return $result;
}
function onError($severity, $message, $file = null, $line = null) {
$this->errors[] = $message;
}
function getErrors() {
return $this->errors;
}
function hasErrors() {
return count($this->errors) > 0;
}
}
そしてユースケース:
$doc = new DomDocument();
$doc->load($xml_filename);
$validation = new errorhandler_LoggingCaller();
$validation->call(
array($doc, 'schemaValidate'),
array($xsd_filename));
if ($validation->hasErrors()) {
var_dump($validation->getErrors());
}
私見のベストプラクティスは、次のアプローチを使用することです。1.エラー/例外ハンドラーを作成します2.アプリの起動時に開始します3.そこからすべてのエラーを処理します
<?php
class Debug {
public static setAsErrorHandler() {
set_error_handler(array(__CLASS__, '__error_handler'));
}
public static function __error_handler($errcode, $errmsg, $errfile, $errline) {
if (IN DEV) {
print on screen
}
else if (IN PRO) {
log and mail
}
}
}
Debug::setAsErrorHandler();
?>
未処理のエラーはスクリプトを停止します。それだけで、それらを処理する十分な理由になります。
一般に、Try-Catch ブロックを使用してエラーを処理できます
try
{
// Code that may error
}
catch (Exception $e)
{
// Do other stuff if there's an error
}
ページに表示されるエラーまたは警告メッセージを停止したい場合は、呼び出しの前に @ 記号を付けることができます。
@mysql_query($query);
ただし、クエリでは、何が起こっているのかをよりよく理解できるように、通常、このようなことを行うことをお勧めします。
@mysql_query($query)
or die('Invalid query: ' . mysql_error() . '<br />Line: ' . __LINE__ . '<br />File: ' . __FILE__ . '<br /><br />');
スクリプトが処理しているデータを明示的に制御できない場合は、エラー処理を使用する必要があります。たとえば、フォームの検証などの場所で頻繁に使用する傾向があります。コード内でエラーが発生しやすい場所を特定する方法を知るには、ある程度の練習が必要です。値を返す関数呼び出しの後や、データベース クエリの結果を処理するときに一般的な場所があります。関数からの戻り値が期待どおりであると想定してはいけません。必ず予測してコーディングする必要があります。try/catch ブロックは便利ですが、必ずしも使用する必要はありません。多くの場合、単純な if/else チェックでうまくいきます。
エラー処理は、安全なコーディング プラクティスと密接に関連しています。スクリプトが単純にクラッシュする原因とならない「エラー」が多数あるためです。厳密にはエラー処理自体についてではありませんが、 addedbytes には、安全な PHP プログラミングの基本に関する 4 つの優れた記事シリーズがあり、こちらで見つけることができます。mysql_real_escape_stringやユーザーが入力したデータの内容を確認する際に非常に強力な正規表現などのトピックに関するスタックオーバーフローに関する質問は他にもたくさんあります。
mysql_error を出力するのではなく、ログに保存することができます。そうすれば、エラーを追跡することができ (また、ユーザーに報告してもらう必要がなくなります)、問題を解決することができます。
最良のエラー処理は、ユーザーに透過的な種類のものです。コードに問題を整理させ、そのユーザーの仲間を巻き込む必要はありません。
@ によるエラー抑制は非常に遅いです。
コード内のエラーをすぐに処理するだけでなく、以下を利用することもできます
http://us.php.net/manual/en/function.set-exception-handler.php
および
http://us.php.net/manual/en/function.set-error-handler.php
独自の例外ハンドラを設定すると特に便利です。例外が発生すると、例外の種類に応じてさまざまな操作を実行できます。
例:mysql_connet
呼び出しが返っFALSE
てきたらnew DBConnectionException(mysql_error())
、「特別な」方法でそれを処理します: エラー、DB 接続情報 (ホスト、ユーザー名、パスワード) などをログに記録し、開発チームに電子メールを送信して、何かが本当に間違っている可能性があることを通知します。データベース
これを使用して、標準のエラー処理を補完します。このアプローチを過度に使用することはお勧めしません
また、Google フォームを使用して例外をキャッチして分析することもできます。データベースや公開サーバーを維持する必要はありません。プロセスを説明するチュートリアルがここにあります。