質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.10%

常に例外を取るべきか取らないべきか

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 1,339

aaaaaaaa

score 481

下記のソースは、データベースへ接続するときに例外が発生した場合、例外処理が発生するものです。

try {

//接続
$dsn = "dbname=aaaa;host=localhost";
$user = "root";
$password = "";
$dbh = new PDO($dsn, $user, $password);
$dbh->query("set names utf8");

print "接続しました。";
//接続解除
$dbh = null;

} catch(exception $e) {
    print "ただいま障害が発生しており大変ご迷惑おかけしております。".mb_convert_encoding($e->getMessage(),'UTF-8','JIS,ASCII,CP51932,SJIS-win');
    exit();
}


たまたまネットサーフィンしているときに、データベースに接続する際のことを指南しているサイトを見つけ閲覧していたところ下記のソースが記述してありました。

try {
  $pdo = new PDO('mysql:dbname=phpdb;host=127.0.0.1', 'root', '1234', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
  $pdo->query('SET NAMES utf8');

  $stmt = $pdo->query('SELECT * FROM address WHERE no >= 10 AND no <= 20');
  while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo '<p>' . $data['no'] . ':' . $data['name'] . "</p>\n";
  }
} catch (PDOException $e) {
  exit($e->getMessage());
}

$pdo = null;


http://www.php-labo.net/tutorial/class/pdo.html

PDOの第4引数に何かを指定できること自体、ネットサーフィンをして初めて知りました。第4引数にDB接続中に発生したエラーをどのように通知するかを指定できるATTR_ERRMODEとERRMODE_EXCEPTIONを指定することで
"接続時"以外のエラーが発生したときも一律に例外を投げることが出来るのでソースの記述が短くなります。
ここで疑問ですが、先述の技巧と接続時のエラーのみ例外を投げ、それ以外は、条件分岐などで個別にエラーの対処をするのは、どちらが適当であると思いますか。
ソースが短くなる以外に、何か利点はありますか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

お邪魔します。

難しい問題ですね。意見の分かれるところだと思いますが。

説明のために、異常が発生するケースを分類してみましょう。
異常が発生するケース、というのは大まかに言って

  1. ハードの異常やネットワーク異常など、アプリケーションでは回復不能なエラー
  2. コーディングミスや設計ミスによる不具合(アサーション例外を含める)
  3. 処理の順序や仕様上想定されない操作によって発生する回復可能な例外

このくらいに分類できるのではないか、と思います。

例外というのは何かしらアプリケーションに起きている問題を、開発者やユーザに知らせるための機構であると考えることができます。
アプリケーションの動作のしようがないからアプリケーションを落としてしまうとか、次に登録ボタンを押したときは大丈夫かもしれないから放置で知らんぷりとか、そういうのは設計としてお粗末ですよね。
ロギングを行って異常を回復するための情報を保守開発者に対して残す(ロギングをトリガにメールが飛ぶ機構などもよくありますね)、ユーザに異常を伝えてシステムの管理者や保守を行っている人間に連絡を取るよう促す(=ようするにメッセージの表示、ということになるのかな)、など誰かに異常発生を伝えるためのトリガとなるイベントなんです。

そう考えると異常発生時の挙動の設計がまずあるべきで、1.ならこのエラーはユーザに伝えても仕方がないなとか、いやこれはシステムダウンしてるしエラーページ表示しないとなとか、3.なら先にこのページを開いてこの操作をしてもらわないといけないからユーザにメッセージを表示しようとか、それぞれ例外が発生する状況で要求される動作が自然と決まっていくはずです。

異常を誰にどう伝えるかが決まると、異常発生を捕捉し対応するログ出力やメッセージの表示やページ遷移の処理を記述する必要が出てきます。例外の種類(=異常の原因)によって行うべき処理が異なってくると、一つのcatch節でより抽象的な例外をハンドリングしてコーディングするのはあまり格好が良くなく、どのコードが原因で異常が発生したのかをとらえにくくなってしまいます。

少し話はずれますが、避けることができる例外を発生させる、処理の実現方法として例外を使用するやり方は、混乱を招くのでよくない、とされています。
賛否両論ありますが、先にテーブルのデータを調べておけば発生しない例外、例えばUPDATEするレコードがない時でもあえて一度UPDATEをかけて例外が発生したらインサートに切り替える、などという書き方もありますが、更新を実行して失敗するという無駄な処理(データベース上でもトランザクションが発生し、行やテーブルのロックも起こるでしょう)が実行され、その分処理が遅くなったり、処理によってはデッドロックの危険性を高めたりもするので、先にSELECTをかけてから結果をみてUPDATEをかけるかINSERTをかけるか判断する、といった実装をすることが多いです。(DBサーバ因ってはmergeなんてのがあらかじめ用意されてたりもしますが)

また、2.のアサーション例外はハンドリングするべきでない、というかテストで出ないように潰すべきものですね。バグの原因の特定がしやすいように例外にメッセージを出すのが良いやり方です。例外で落ちると、直さないといけないことがわかりやすくていいです。
デバッグ起動以外では投げられないようにしておくのも、少し黒いですが現実的な考えですね。

少し質問の内容とはズレたところがあったかもしれませんが、例外処理・エラーハンドリングに対する全般的な考え方について思うところを記載してみました。

長々と書きましたが、結論としては、すべて一か所でハンドリングするかそうでないかは、想定される異常と、それぞれの異常発生時にどのような回復処理や通知処理を行うか、また、その処理でどれだけの処理をするか(=SQLを実行するか)、という設計による、というのが回答です。

以上です、参考になりましたら幸いです。

追伸

自分は本職がjava書きなもので、java言語だと例外処理についてこういう議論がなされてるよ、という参考リンクを張っておきます。質問の内容からするとぐっと深いところですが、例外マスターになれるかも?!
参考まで。
Java のチェック例外と非チェック例外の考察まとめ

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る