[解決済み] 例外をキャッチして再スローするためのベストプラクティスは何ですか?
質問
キャッチした例外はそのまま再スローすべきですか、それとも新しい例外にラップすべきですか?
つまり、こうすればいいのか。
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
} catch (Exception $e) {
throw $e;
}
またはこれです。
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
} catch (Exception $e) {
throw new Exception("Exception Message", 1, $e);
}
という答えが返ってきた場合 直接投げる を使うことを提案してください。 例外の連鎖 例外チェーニングを使用する現実的なシナリオを理解することができません。
どのように解決するのですか?
例外をキャッチしてはいけない 意味のあることをするつもりがない限り .
何か意味のあること"は、この中の一つかもしれません。
例外処理
最も明白で意味のある行動は、エラーメッセージを表示し、操作を中断するなどして、例外を処理することです。
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
ロギングまたは部分クリーンアップ
時には、特定のコンテキストで例外を適切に処理する方法がわからないことがあります。おそらく、全体像に関する情報が不足しているのでしょうが、障害が発生した時点にできるだけ近いところでログを取りたいものです。このような場合、catch、log、re-throwを行いたいかもしれません。
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
関連するシナリオとして、失敗した操作の後始末を行うには適切な場所にいるが、失敗をトップレベルでどのように処理すべきかを決定することができない場合があります。以前のバージョンの PHP では、これは次のように実装されていました。
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
catch (Exception $e) {
$connect->disconnect(); // we don't want to keep the connection open anymore
throw $e; // but we also don't know how to respond to the failure
}
PHP 5.5で導入された
finally
キーワードを使用することで、クリーンアップのシナリオに別のアプローチで対応できるようになりました。クリーンアップのコードが、何が起こったかに関係なく (すなわち、エラー時と成功時の両方で) 実行される必要がある場合、スローされた例外が伝播するのを透過的に許容しながら、これを実行することが可能になりました。
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
エラーの抽象化(例外チェインによる)
3つ目のケースは、起こりうる多くの障害を論理的に大きな傘の下にまとめたい場合である。論理的なグループ分けの例
class ComponentInitException extends Exception {
// public constructors etc as in Exception
}
class Component {
public function __construct() {
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);
}
}
}
この場合、ユーザは
Component
データベース接続を使用して実装されていることを知られないようにするためです (将来的にはファイルベースのストレージを使用するという選択肢も残されているかもしれません)。そのため
Component
初期化に失敗した場合、次のように記述します。
ComponentInitException
がスローされます。これによって
Component
の例外をキャッチすることができます。
の詳細(実装に依存する)にアクセスすることができます。
.
よりリッチなコンテキストの提供 (例外チェインによる)
最後に、例外に対してより多くのコンテキストを提供したい場合があります。この場合、例外を別の例外でラップして、エラーが発生したときに何をしようとしていたのか、より多くの情報を保持するのが理にかなっています。たとえば、以下のようになります。
class FileOperation {
public static function copyFiles() {
try {
$copier = new FileCopier(); // the constructor may throw
// this may throw if the files do no not exist
$copier->ensureSourceFilesExist();
// this may throw if the directory cannot be created
$copier->createTargetDirectory();
// this may throw if copying a file fails
$copier->performCopy();
}
catch (Exception $e) {
throw new Exception("Could not perform copy operation.", 0, $e);
}
}
}
このケースは上記と似ていますが(そして、この例はおそらく人が考えつく最高のものではありません)、より多くのコンテキストを提供することのポイントを説明しています:もし例外が投げられたら、それはファイルコピーが失敗したことを教えてくれるのです。しかし なぜ は失敗したのでしょうか?この情報はラップされた例外の中で提供されます(この例がもっと複雑なものであれば、複数のレベルが存在する可能性があります)。
を作成するシナリオを考えてみると、この方法の価値がよくわかる。
UserProfile
なぜなら、ユーザープロファイルはファイルに格納されており、トランザクションセマンティックをサポートしているからです。
この場合、もしあなたが
try {
$profile = UserProfile::getInstance();
}
という例外エラーが発生した場合、混乱するのは当然でしょう。この "core" 例外を、コンテキストを提供する他の例外の層でラップすると、エラーへの対処がはるかに容易になります("プロファイル コピーの作成に失敗しました" -> "File copy operation failed" -> "Target directory could not be created").
関連
-
[解決済み] SAJAXは死んだか?何を置き換えるべきか?
-
[解決済み】foreach()に与えられた引数が無効です。)
-
[解決済み] $wpdb->update または $wpdb->insert を実行すると、引用符の前にスラッシュが追加される
-
[解決済み】Laravel 5.2 Storage::makeDirectory($dir) でディレクトリが作成されない。
-
[解決済み】既に開始されているPHPセッション【重複あり
-
[解決済み】/var/www/htmlとは何ですか?[クローズド]
-
[解決済み] Long-Polling、Websocket、Server-Sent Events (SSE)、Cometとは何ですか?
-
[解決済み] パブリック、プライベート、プロテクトの違いは何ですか?
-
[解決済み] Javaにおける例外処理によるパフォーマンスへの影響とは?
-
[解決済み】Exceptionを投げるとき、どの部分が高価なのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】XAMPPポート80をPID 4の「Unable to open process」が使用中 [重複] XAMPPポート80をPID 4の「Unable to open process」が使用中。]
-
[解決済み] [Solved] Fatal error: メンバ関数bind_param()のbooleanに対する呼び出し [重複] [重複
-
[解決済み】不明なMySQLサーバーのホスト
-
[解決済み】mysqli_result クラスのオブジェクトを文字列に変換できない
-
[解決済み】変な電話番号を生成するフェイカー?
-
[解決済み】php, mysql - データベースへの接続数が多すぎるエラー
-
[解決済み】XAMPPエラー: www.example.com:443:0 サーバー証明書に、サーバー名と一致するIDが含まれていません。
-
[解決済み] [Solved] Fatal error: 非オブジェクトのメンバ関数fetch_assoc()の呼び出し [重複]。
-
[解決済み】Wordpressの子テーマのstyle.cssが効かない。
-
[解決済み] SSLエラー SSL3_GET_SERVER_CERTIFICATE:証明書の検証に失敗しました。