かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

PHP5 例外処理でエラーをぶん投げ(throw)たらPHPのエラーになった。

クラス内の関数で処理をしてエラーがあればExceptionでthowして呼び出し元でエラーを表示させようとしていた所次のようなエラーが出てしまいました。
Fatal error: Uncaught exception 'Exception' with message ...

エラーになったコード

<?php
class User {
  public function getByID($ID = null) {
    if( !empty($ID) ) {
      try {
        // DBからデータを取ってきたりとかする
      } catch( PDOException $e ) {
        throw $e;
      }
    } else {
      throw new Exception('IDがないよー');
    }
  }
  return $data;
}

$User = new User();
try {
  $User->getByID($ID);
} catch( PDOException $e ) {
  echo 'ERROR: ' . $e->getMessage();
}

$IDがなくthrow new Exception('IDがないよー');で例外処理が帰ってくるときにFatal errorが発生していました。

エラーをthrowする側とキャッチする側が一致していないのが問題!?

Fatal errorが発生している時、例外をthrowする側はExceptionですが、例外を最終的にcatchしているのがPDOExceptionになっているのが問題でした。

PDOException クラスRuntimeExceptionクラスを継承しており
RuntimeExceptionクラスExceptionクラスを継承しています。

どうやらPDOExceptionクラスでは継承元のExceptionクラスでの例外をキャッチできないので、Uncaughtというエラーになってしまっていたようです。
最終的にキャッチする部分を大本の継承元であるExceptionにしてしまえばエラーになりませんでした。

<?php
class User {
  public function getByID($ID = null) {
    if( !empty($ID) ) {
      try {
        // DBからデータを取ってきたりとかする
      } catch( PDOException $e ) {
        throw $e;
      }
    } else {
      throw new Exception('IDがないよー');
    }
  }
  return $data;
}

$User = new User();
try {
  $User->getByID($ID);
} catch( Exception $e ) {
  // PDOException も Exception もココでハートキャッチ。
  echo 'ERROR: ' . $e->getMessage();
}

 
Exceptionでの例外はPDOExceptionではcatchできない事を利用すれば、例外の種類ごとにエラーを出し分けることもできます。

<?php
class User {
  public function getByID($ID = null) {
    if( !empty($ID) ) {
      try {
        // DBからデータを取ってきたりとかする
      } catch( PDOException $e ) {
        throw $e;
      }
    } else {
      throw new Exception('IDがないよー');
    }
  }
  return $data;
}

$User = new User();
try {
  $User->getByID($ID);
} catch( PDOException $e ) {
  // PDOException の場合のみ
  echo 'PDOException: ' . $e->getMessage();
} catch( Exception $e ) {
  // PDOException でキャッチできなかった例外はこっち 
  echo 'Exception: ' . $e->getMessage();
}

上の例では$IDが無ければException: IDがないよーと表示され、
PDOのエラーとかが有った時はPDOException: ERROR MESSAGE...と表示されるようになりました。
 


[参考]