PHP 例外処理
例外は、指定されたエラーが発生したときにスクリプトの通常のフローを変更するために使用されます。
例外とは
PHP 5 は、新しいオブジェクト指向のエラー処理方法を提供します。
例外処理は、指定されたエラー(例外)状況が発生したときにスクリプトの通常のフローを変更するために使用されます。この状況を例外と呼びます。
例外がトリガーされると、通常は次のことが発生します:
- 現在のコードの状態が保存される
- コードの実行が、事前定義(カスタム)された例外ハンドラ関数に切り替えられる
- 状況に応じて、ハンドラは保存されたコードの状態からコードの実行を再開するか、スクリプトの実行を終了するか、コード内の別の場所からスクリプトの実行を続行する場合があります。
さまざまなエラー処理方法を紹介します。
- 例外の基本的な使い方
- カスタム例外ハンドラの作成
- 複数の例外
- 例外の再スロー
- トップレベルの例外ハンドラの設定
注記:例外はエラー状況でのみ使用すべきであり、指定されたポイントからコードの別の場所にジャンプするために使用すべきではありません。
例外の基本的な使い方
例外がスローされると、その後のコードは実行されず、PHP は一致する "catch" コードブロックを探します。
例外がキャッチされず、set_exception_handler() を使用した対応する処理も行われていない場合、重大なエラー(致命的エラー)が発生し、"Uncaught Exception"(未捕捉の例外)というエラーメッセージが出力されます。
例外をスローして、それをキャッチしない例を試してみましょう:
上記のコードでは、次のようなエラーが発生します:
Fatal error: Uncaught exception 'Exception' with message 'Value must be 1 or below' in /www/サンプル/test/test.php:7 Stack trace: #0 /www/サンプル/test/test.php(13): checkNum(2) #1 {main} thrown in /www/サンプル/test/test.php on line 7
Try、throw、catch
上記の例で発生したエラーを回避するには、例外を処理する適切なコードを作成する必要があります。
適切な例外処理コードには次のものが含まれる必要があります:
- Try - 例外を使用する関数は "try" コードブロック内に配置する必要があります。例外がトリガーされなければ、コードは通常どおり実行されます。ただし、例外がトリガーされると、例外がスローされます。
- Throw - 例外をどのようにトリガーするかを定義します。各 "throw" には少なくとも1つの "catch" が対応する必要があります。
- Catch - "catch" コードブロックは例外をキャッチし、例外情報を含むオブジェクトを作成します。
例外をトリガーしてみましょう:
上記のコードでは、次のようなエラーが発生します:
Message: 变量值必须小于等于 1
例の説明:
上記のコードは例外をスローし、それをキャッチしました:
- checkNum() 関数を作成します。これは数値が1より大きいかどうかをチェックします。大きい場合は例外をスローします。
- "try" コードブロック内で checkNum() 関数を呼び出します。
- checkNum() 関数内で例外がスローされます。
- "catch" コードブロックはその例外を受け取り、例外情報を含むオブジェクト ($e) を作成します。
- この exception オブジェクトから $e->getMessage() を呼び出すことで、その例外からのエラーメッセージを出力します。
ただし、「各 throw は1つの catch に対応する必要がある」という原則に従うために、トップレベルの例外ハンドラを設定して、見逃したエラーを処理することができます。
カスタム Exception クラスを作成する
カスタム例外ハンドラの作成は非常に簡単です。専用のクラスを作成し、PHP で例外が発生したときにその関数を呼び出せるようにします。このクラスは exception クラスの拡張である必要があります。
このカスタム customException クラスは、PHP の exception クラスのすべてのプロパティを継承しており、カスタム関数を追加できます。
customException クラスの作成を始めましょう:
この新しいクラスは、古い exception クラスのコピーに errorMessage() 関数を追加したものです。古いクラスのコピーであるため、古いクラスからプロパティとメソッドを継承しており、getLine()、getFile()、getMessage() などの exception クラスのメソッドを使用できます。
例の説明:
上記のコードは例外をスローし、カスタム exception クラスを使用してそれをキャッチします:
- customException() クラスは、古い exception クラスの拡張として作成されます。これにより、古い exception クラスのすべてのプロパティとメソッドを継承します。
- errorMessage() 関数を作成します。e-mail アドレスが有効でない場合、この関数はエラーメッセージを返します。
- $email 変数に有効でない e-mail アドレスの文字列を設定します。
- "try" コードブロックを実行すると、e-mail アドレスが有効でないため、例外がスローされます。
- "catch" コードブロックは例外をキャッチし、エラーメッセージを表示します。
複数の例外
1つのスクリプトで複数の例外を使用して、さまざまな状況を検出できます。
複数の if..else コードブロック、または1つの switch コードブロック、または複数の例外をネストして使用できます。これらの例外は異なる exception クラスを使用し、異なるエラーメッセージを返すことができます:
例の説明:
上記のコードは2つの条件をテストし、いずれかの条件が満たされない場合は例外をスローします:
- customException() クラスは、古い exception クラスの拡張として作成されます。これにより、古い exception クラスのすべてのプロパティとメソッドを継承します。
- errorMessage() 関数を作成します。e-mail アドレスが有効でない場合、この関数はエラーメッセージを返します。
- $email 変数に、有効な e-mail アドレスであるが文字列 "example" を含む文字列を設定します。
- "try" コードブロックを実行すると、最初の条件では例外はスローされません。
- e-mail に文字列 "example" が含まれているため、2番目の条件が例外をトリガーします。
- "catch" コードブロックは例外をキャッチし、適切なエラーメッセージを表示します。
customException クラスが例外をスローしたが、customException をキャッチせず、base exception のみをキャッチした場合は、そこで例外が処理されます。
例外の再スロー
場合によっては、例外がスローされたときに、標準とは異なる方法で処理したいことがあります。その場合は、"catch" コードブロック内で例外を再スローできます。
スクリプトはシステムエラーをユーザーから隠すべきです。システムエラーはプログラマーにとっては重要かもしれませんが、ユーザーはそれに興味がありません。ユーザーにとって使いやすくするために、ユーザーにとってわかりやすいメッセージを含む例外を再スローできます:
例の説明:
上記のコードは、メールアドレスに文字列 "example" が含まれているかどうかをチェックします。含まれている場合は、例外を再スローします:
- customException() クラスは、古い exception クラスの拡張として作成されました。これにより、古い exception クラスのすべてのプロパティとメソッドを継承します。
- errorMessage() 関数を作成します。e-mail アドレスが無効な場合、この関数はエラーメッセージを返します。
- $email 変数を、有効な e-mail アドレスであるが文字列 "example" を含む文字列に設定します。
- "try" コードブロックは別の "try" コードブロックを含み、これにより例外を再度スローできます。
- e-mail が文字列 "example" を含むため、例外がトリガーされます。
- "catch" コードブロックはその例外をキャッチし、"customException" を再スローします。
- "customException" がキャッチされ、エラーメッセージが表示されます。
現在の "try" コードブロックで例外がキャッチされない場合、より高いレベルで catch コードブロックを探します。
トップレベルの例外ハンドラを設定する
set_exception_handler() 関数は、キャッチされていないすべての例外を処理するユーザー定義関数を設定できます。
上記のコードの出力は次のようになります:
Exception: Uncaught Exception occurred
上記のコードでは、"catch" コードブロックは存在せず、代わりにトップレベルの例外ハンドラがトリガーされます。この関数を使用して、キャッチされていないすべての例外をキャッチする必要があります。
例外のルール
- 例外処理が必要なコードは、潜在的な例外をキャッチするために try コードブロック内に置く必要があります。
- 各 try または throw コードブロックには、少なくとも1つの対応する catch コードブロックが必要です。
- 複数の catch コードブロックを使用すると、さまざまな種類の例外をキャッチできます。
- try コードブロック内の catch コードブロックで例外をスロー(再スロー)できます。
要するに:例外がスローされた場合は、それをキャッチする必要があります。
その他の拡張