PDO の例外処理(try-catch とエラーモード設定)
PDO を使うとき、エラー処理の設定を最初に済ませておくかどうかで、デバッグ効率が大きく変わる。PDO にはエラーモードという仕組みがあり、エラー発生時の挙動を 3 段階で制御できる。
エラーモードの種類
PDO のエラーモードは setAttribute メソッドで設定する。指定できるモードは 3 つある。
エラーが起きても何も報告しない。開発者が自分で errorCode や errorInfo を呼んで確認する必要がある。バグに気づきにくいため、開発時には不向きだ。
エラー発生時に PDOException をスローする。try-catch で捕捉でき、問題箇所が即座にわかる。開発・本番ともに推奨される設定である。
もう 1 つ ERRMODE_WARNING というモードもあり、PHP の警告(E_WARNING)を発生させるが、処理は続行する。中途半端なため実務ではほぼ使われない。
エラーモードの設定方法
接続時のオプション配列で指定するのが一般的だ。
$pdo = new PDO(
'mysql:host=localhost;dbname=mydb;charset=utf8mb4',
'user',
'password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]
);setAttribute で後から変更することもできる。
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );どちらでも動作は同じだが、接続時にまとめて指定するほうがコードの見通しがよい。
try-catch で例外を捕捉する
ERRMODE_EXCEPTION を設定すると、SQL の構文ミスや接続エラーなど、あらゆる PDO 関連のエラーが PDOException として投げられる。これを try-catch で受け取る。
try
{
$pdo = new PDO(
'mysql:host=localhost;dbname=mydb;charset=utf8mb4',
'user',
'password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]
);
$stmt = $pdo->prepare( 'SELECT * FROM users WHERE id = :id' );
$stmt->bindParam( ':id', $id, PDO::PARAM_INT );
$stmt->execute();
}
catch ( PDOException $e )
{
echo 'データベースエラー: ' . $e->getMessage();
}PDOException は PHP 標準の RuntimeException を継承しているため、catch ( Exception $e ) でも捕捉可能だ。ただし PDOException で受け取るほうが、データベース固有のエラー情報にアクセスしやすい。
PDOException から取得できる情報
PDOException には以下の情報が含まれる。
| メソッド / プロパティ | 取得できる内容 |
|---|---|
| getMessage() | エラーメッセージ |
| getCode() | SQLSTATE エラーコード |
| errorInfo | ドライバ固有のエラー情報 |
たとえばテーブル名を間違えた場合、getMessage() は「SQLSTATE[42S02]: Base table or view not found」のようなメッセージを返す。これだけで原因の特定が容易になる。
本番環境での注意点
開発環境ではエラーメッセージをそのまま表示して問題ないが、本番環境ではエラーの詳細をユーザーに見せてはいけない。テーブル名やカラム名が漏洩するとセキュリティリスクになるためだ。
catch ( PDOException $e )
{
error_log( $e->getMessage() );
echo 'システムエラーが発生しました。';
}error_log でサーバーのログファイルに記録し、ユーザーには汎用的なメッセージだけを表示する。この使い分けが本番運用の基本となる。