■PHPにおける「エラー」と「例外」の違い
- 例外はオブジェクトであり、エラーが起こったときにthrowされる
- 例外はハンドリングすることが可能、(継承させた)例外のタイプで条件分けできる
- 例外はハンドリングされていない場合、全てfatalである
- 例外は発生時にインスタンス化され、コンストラクタが実行される
- 例外はコードの処理の流れを変える
■Exceptionクラス
以下のような実装になっている。但し、ビルトインクラスであり、ユーザーが記述する必要はない。
<?php class Exception { protected $message = 'Unknown Exception'; protected $code = 0; protected $fill; protected $line; function __construct($message = null, $code = 0); final function getMessage(); final function getCode(); final function getFile(); final function getLine(); final function getTrace(); final function getTranceAsString(); function __toString(); } ?>
Exceptionクラスは継承して効果的にユーザー仕様の例外を実装することができる。以下のようにPDOにおいても垣間見ることができる。
<?php try { $dsn = 'mysql:host=localhost;dbname=dbname'; $dbh = new PDO($dsn, DB_USER, DB_PASS); $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e){ print('Exception: ' . $e->getMessage()); } ?>
class PDOException extends Exceptionしてる部分と、new PDOExceptionしてるコードがあるってことだな。。。
■例外の発生
通常、throw文によるエラーが起こったときに、例外はインスタンス化され発生する。
<?php throw new Exception('an error occurs');//Fatal error: Uncaught exception 'Exception' with message 'an error occurs' ?>
例外はユーザー定義した例外や通常の例外まで伝播する。例外が発生する可能性がある場合、一般的には以下のようにtry~catch…ブロックが用いて例外をハンドリングする。
<?php try { $dsn = 'mysql:host=localhost;dbname=dbname'; $dbh = new PDO($dsn, DB_USER, DB_PASS); $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e){ print('PDOException: ' . $e->getMessage()); } ?>
また、伝播する例外を分別してキャッチするには以下のようなコードを使う。tryをネストすることも可能だが見にくくなるので以下のような形が望ましい。
<?php class MyException extends Exception {} try { $dsn = 'mysql:host=localhost;dbname=dbname'; $dbh = new PDO($dsn, DB_USER, DB_PASS); $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //throw new MyException(); } catch(MyException $e){ print('MyException: ' . $e->getMessage()); } catch(PDOException $e){ print('PDOException: ' . $e->getMessage()); } catch(Exception $e){ print('Exception: ' . $e->getMessage()); } ?>
例外はcatchできればスクリプトの実行は止まらない。しかし、キャッチしきれないとFatal errorが起こりスクリプトの実行は止まってしまう。キャッチしきれない(ハンドリングされていない例外が発生した)ときは、以下のようにして挙動を定義することができる。但し、この場合でもスクリプトの実行が止まることに変わりはない。
<?php function handleUncaughtException($e){ print($e->getMessage()); } set_exception_handler('handleUncaughtException'); throw new Exception('my error');//my error ?>
なんらかの事情で一括してハンドリングされていない例外の挙動を変更したい場合に有用なのかもしれない。