Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

例外を使う

via. http://d.hatena.ne.jp/uratch/20100303/12675871652010-03-18 - ます’s Diary - どうでもいい事100選

前のエントリにも続きますが、Javaっぽく書くのであれば、例外を使うのもそうかもしれません。

一番のメリットが、ロジックの中にCライク(?)な"戻り値が0だったら〜、そうじゃなかったら〜"みたいな処理を書かなくて済むのと、例外をcatchする箇所を絞って、エラー処理をまとめて書ける事じゃないかと思います。
たとえば、"DBに繋いでデータを取得するコード"を考えてみます。例外を使わない場合は次のようなコード。

<?php
$conn = oci_connect("scott", "tiger", $db);
if ($conn === false) {
    // エラー処理
}

$stmt = oci_parse($conn, "...");
if ($stmt === false) {
    // エラー処理
}

if (oci_execute($stmt, OCI_DEFAULT) === false) {
    // エラー処理
}

while (oci_fetch($stmt)) {
    // データ処理
}

例外を使うとこんな感じ(ホントはoci関数は例外を投げません。イメージです)。

<?php
try {
    $conn = oci_connect("scott", "tiger", $db);
    $stmt = oci_parse($conn, "...");
    oci_execute($stmt, OCI_DEFAULT);
    while (oci_fetch($stmt)) {
        // データ処理
    }
} catch (Exception $e) {
    // エラー処理
}

実際のエラー処理は、上のコードのような箇所ではなく、それを呼び出した側のコード、あるいはフレームワークに近い"層"で書くことが多い感じです。逆に、ビジネスロジック実行・クエリ実行などの"具体的な処理"をするコードになればなるほど、『処理してエラーが発生したら、とりあえず例外を投げるだけ』にしてます。
catchするタイミングですが、その例外が『予期している』のか『予期していない』のかで、どの層でcatchするかが違ってきます。たとえば、エラー時に何らかの処理を行う予定がある(必須パラメータがが入力されていない場合に入力を促すメッセージを表示するとか)場合は、『予期している例外』を呼び出した側(ActionクラスとかService/Logicクラス)でcatchし、然るべき処理をします。
逆に、それ以外の例外は『予期していない例外』になります。DB接続に失敗した時に投げられる例外や、あるはずのデータが無くて処理に失敗した時に投げられる例外、とかです。こちらはActionなどでもcatchしないで、フレームワークで一括に処理(ゴメンナサイ画面とか"ただいま混み合ってます"画面を出すとか)させることが多いです。
Webアプリの場合、個人的には

  • ProjectException extends Exception
    • UnauthenticatedException extends ProjectException
    • ApplicationException extends ProjectException
      • InvalidRequestMethodException extends ApplicationException
      • NotFoundException extends ApplicationException
    • ApplicationError extends ProjectException

みたいな例外を作っておいて、UnauthenticatedExceptionをcatchした場合はログイン画面を出す(HTTP401を返すことも)、ApplicationExceptionの場合はエラーメッセージとHTTP403、ApplicationErrorの場合はゴメンナサイ画面を出しつつHTTP500を返す、といったことをしてます。SQLExceptionとか処理系固有の例外もApplicationErrorと同じ扱いにします。ちなみに、catchしたタイミングでtrace情報のロギングなどもしてます。

catchする側はちょっと面倒かもしれませんが、ロジック側を『なんかあったら例外投げとけ』という具合にシンプルに記述できるのは楽です:-)