2010年4月1日木曜日

PHP:エラー処理いろいろ

例外について書いていて、本当に楽になるのかエラー処理を何通りか書いてみたくなりました。元ネタはこちらのページで、コードをそれっぽく写したものです。


コード#1:エラー処理なし

まずはエラー処理無しの場合。
なんてシンプルなんでしょう。これで納品できれば天国のような(後で地獄になるような)世界ですね。

$conn = DB::connect( 'test', 'test' );
$stmt = DB::parse( $conn, 'sql statement' );
DB::execute( $stmt );
$num  = DB::num_row();
for( $i = 0; $i < $num; $i ++ ) {
  DB::fetchRow($i);
}

コード#2:if文でネストしたエラー処理 

ここに適当にエラー処理を書加えてみます。
これはif文をネスとして処理を行ってます。こんな単純な処理にもかかわらず、ネストが4重(3重か?)になってます。これで処理が20行とか続いたらバグ発生率が高くなりそう。

$conn = DB::connect( 'test', 'test' );
if( $conn === FALSE ) {
  $error_msg = "DBにつながりません";
}
else {
  $stmt = DB::parse( $conn, 'sql statement' );
  if( $stmt === FALSE ) {
    $error_msg = "SQLが理解できません";
  }
  else {
    DB::execute( $stmt );
    $num  = DB::num_row();
    if( !$num ) {
      $error_msg = "データが存在しません";
    }
    else {
      for( $i = 0; $i < $num; $i ++ ) {
        DB::fetchRow($i);
        // 何か処理しよう
      }
    }
  }
}

コード#3:連続したif文のエラー処理 

深いネストは嫌いなので、出来るだけネストしないよう、elseで続けてみます。が、一箇所大変なことになってます。こんなコード書いたら・・・

if( !$conn = DB::connect( 'test', 'test' ) ) {
  $error_msg = "DBにつながりません";
}
else 
if( !$stmt = DB::parse( $conn, 'sql statement' ) ) {
  $error_msg = "SQLが理解できません";
}
else 
if( DB::execute( $stmt ) || TRUE ) {
  // こんなコード書いたら仕事失うかも・・・
}
else 
if( !$num  = DB::num_row() ) {
  $error_msg = "データが存在しません";
}
else {
  for( $i = 0; $i < $num; $i ++ ) {
    DB::fetchRow($i);
    // 何か処理しよう
  }
}

こう書き直してみようかな。
それでも、何となく気に入らないなぁ。
DB::executeの戻り値が分からないので、怪しいコードです。

else 
if( DB::execute( $stmt ) &&
    !$num  = DB::num_row() ) {
  $error_msg = "データが存在しません";
}

コード#4:例外を使ったエラー処理 

では例外をメッセンジャーみたいに使ってみた例です。
こういう使い方をしていいのかどうか、実はよく知らないのですが、まぁ、これはこれで動きます。メンテもやりやすそうです。例外投げると遅くなるらしいですが、めったに投げるエラーではなさそうなのでOKではないでしょうか?

class AppException extends Exception {}
try {
  if( !$conn = DB::connect( 'test', 'test' ) ) {
    throw new AppException( 'DBにつながりません' );
  }
  if( !$stmt = DB::parse( $conn, 'sql statement' ) ) {
    throw new AppException( 'SQLが理解できません' );
  }
  DB::execute( $stmt );
  if( ! $num  = DB::num_row() ) {
    throw new AppException( 'データが存在しません' );
  }
  for( $i = 0; $i < $num; $i ++ ) {
    DB::fetchRow($i);
    // 何か処理しよう
  }
}
catch( AppException $e ) {
  $error_msg = $e->getMessage();
}

コード#4b:DBが例外を投げる場合のエラー処理 

最後に、この「DB」なるクラスが例外を投げる場合。
かつ、DBが例外投げたら外でキャッチしてOKな場合です。
もうちょっとシンプルになりますね。

class AppException extends Exception {}
try {
  $conn = DB::connect( 'test', 'test' );
  $stmt = DB::parse( $conn, 'sql statement' );
  DB::execute( $stmt );
  if( ! $num  = DB::num_row() ) {
    throw new AppException( 'データが存在しません' );
  }
  for( $i = 0; $i < $num; $i ++ ) {
    DB::fetchRow($i);
    // 何か処理しよう
  }
}
catch( AppException $e ) {
  $error_msg = $e->getMessage();
}
catch( Exception $e ) {
  $error_msg = "申し訳ありませんッ!";
}

まとめ・・・のようなもの

例外を使ってエラーメッセージを処理すると楽になるかどうかですが、
後から条件を追加するのが楽だった気がします。何しろエラーと一緒にメッセージも飛ばせるので、余りコードを追いかけることなく変更できると思います。

0 件のコメント: