PHPの基礎 - 例外処理
概要
例外処理は、プログラムの実行中に予期せぬエラーが発生した場合、通常の処理フローを中断して特別な対応を行うための仕組みである。
PHPでは、エラーが発生した箇所から即座に処理を中断して、適切なエラー処理ルーチンにジャンプすることができる。
try
ブロックではエラーが発生する可能性のあるコードを配置して、catch
ブロックでは発生した例外を受け取って適切な処理を行う。
オプションでfinally
ブロックを追加することができ、例外の発生有無に関わらず必ず実行する処理を記述する。
例外を投げる場合は、throw
キーワードを使用する。
PHPには、状況に応じた様々な例外クラスが用意されている。
- LogicException
- プログラムのロジックに関するエラー
- RuntimeException
- 実行時のエラー
独自の例外クラスを定義することにより、アプリケーション固有のエラー状況をより適切に表現できる。
例えば、データベース関連のエラーにはDatabaseException、ファイル操作のエラーにはFileOperationException等、目的に応じた例外クラスを定義できる。
例外処理では、より具体的な例外から順に処理を記述して、最後に一般的な例外を捕捉するという階層的な方法が推奨される。
これにより、エラーの種類に応じて適切な対応が可能になる。
捕捉した例外オブジェクトからは、エラーメッセージ、エラーコード、発生場所 (ファイル名と行番号)、スタックトレース等の重要な情報を取得できる。
これらの情報は、デバッグやエラーログの記録に活用される。
重大な例外が発生した場合は、システムのログにその内容を記録することが推奨される。
ただし、セキュリティ上の観点から、エンドユーザに表示するエラーメッセージには詳細な技術情報を含めないよう注意が必要である。
開発時には、予期できる例外は明示的にキャッチして、適切な対応を実装することが重要である。
また、例外を投げ直すことで、より上位の層で統一的なエラー処理を行うことも可能である。
※注意
例外処理は、プログラムの堅牢性を高めるための重要な機能であるが、過度な使用は避けるべきである。
通常の制御フローとして扱えるケースでは、条件分岐等の一般的な制御構文を使用することが推奨される。
基本的な例外処理
PHPでは、try-catchブロックを使用して例外を処理する。
例外オブジェクトには役立つメソッドが用意されており、
getMessageメソッドでエラーメッセージ、getCodeメソッドでエラーコード、getFileメソッドおよびgetLineメソッドでエラーが発生したファイルと行番号を取得できる。
try {
// 例外が発生する可能性のある処理
throw new Exception("エラーが発生");
}
catch (Exception $e) {
// 例外を処理する処理
echo $e->getMessage();
}
finally {
// 必ず実行される処理
}
以下の例では、複数の例外をキャッチしている。
try {
// 危険な処理
}
catch (DatabaseException $e) {
// データベース関連の例外処理
}
catch (FileNotFoundException $e) {
// ファイル関連の例外処理
}
catch (Exception $e) {
// その他の例外処理
}
以下の例では、PDOの例外をキャッチして、ログに記録した後、より適切なカスタム例外を投げ直している。
これにより、システム全体で一貫した例外処理が可能になる。
try {
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "password");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $userId]);
}
catch (PDOException $e) {
error_log("データベースエラー: " . $e->getMessage());
throw new DatabaseException("データベース接続に失敗");
}
カスタム例外クラス
独自の例外クラスを定義することにより、より具体的なエラー処理が可能になる。
class DatabaseException extends Exception
{
public function __construct($message, $code = 0) {
parent::__construct($message, $code);
}
}
バックスラッシュの有無
- バックスラッシュなし(Exception)の場合
- まず、現在の名前空間内でExceptionクラスを探す。
- グローバル名前空間のExceptionクラスにフォールバックする。
- バックスラッシュあり(\Exception)の場合
- 直接グローバル名前空間のExceptionクラスを参照する。
- より明示的で安全な記述である。
- 特に名前空間を使用している場合は、バックスラッシュを付けることを推奨する。
- 意図しない名前解決の衝突を防げる。
- コードの意図が明確になる。
- 実行速度がわずかに速くなる。(名前空間の解決プロセスをスキップできるため)
try {
// 処理
}
catch (Exception $e) {
// エラー処理
}
try {
// 処理
}
catch (\Exception $e) {
// エラー処理
}
以下の例のような場合、バックスラッシュを付けることにより、確実にPHPの標準Exceptionクラスを参照することができる。
namespace MyApp\Controllers;
try {
// 処理
}
catch (\Exception $e) { // グローバル名前空間のExceptionを明示的に指定
// エラー処理
}