PHPの基礎 - 例外処理

提供:MochiuWiki : SUSE, EC, PCB
2024年11月6日 (水) 17:13時点におけるWiki (トーク | 投稿記録)による版 (ページの作成:「== 概要 == 例外処理は、プログラムの実行中に予期せぬエラーが発生した場合、通常の処理フローを中断して特別な対応を行うための仕組みである。<br> PHPでは、エラーが発生した箇所から即座に処理を中断して、適切なエラー処理ルーチンにジャンプすることができる。<br> <br> <code>try</code>ブロックではエラーが発生する可能性のあるコードを配置し…」)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
ナビゲーションに移動 検索に移動

概要

例外処理は、プログラムの実行中に予期せぬエラーが発生した場合、通常の処理フローを中断して特別な対応を行うための仕組みである。
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を明示的に指定
    // エラー処理
 }