PHP 例外処理

❮ 前章へ 次章へ ❯

例外は、指定のエラーが発生した場合に、スクリプトの通常のフローを変更するために使用します。


例外とは?

PHP 5では、エラーに対処する新しいオブジェクト指向の方法が登場しました。

例外処理は、指定のエラー(例外)状態が発生した場合に、コード実行の通常の流れを変更するために使用します。この状態のことを例外といいます。

次は、例外がトリガされたときに通常発生します:

さまざまなエラー処理方法を次に示します:

注: 例外はエラー状態でのみ使用する必要があります。指定したポイントでコード内の別の場所にジャンプするために使用しないでください。


例外の基本的な使用

例外がスローされると、それに続くコードは実行されず、PHPは一致する "catch"ブロックを見つけようとします。

例外がキャッチされない場合、"Uncaught Exception" メッセージの致命的なエラーが発行されます。

キャッチブロックのない例外をスローします:

<?php
//create function with an exception
function checkNum($number) {
  if($number>1) {
    throw new Exception("Value must be 1 or below");
  }
  return true;
}

//trigger exception
checkNum(2);
?>

上のコードは次のようなエラーになります:

Fatal error: Uncaught exception 'Exception'
with message 'Value must be 1 or below' in C:\webfolder\test.php:6
Stack trace: #0 C:\webfolder\test.php(12):
checkNum(28) #1 {main} thrown in C:\webfolder\test.php on line 6

Try、throw および catch

上の例のエラーを回避するには、例外を処理するための適切なコードを作成する必要があります。

適切な例外コードには次のものを含める必要があります:

  1. Try - 例外を使用する関数は "try" ブロック内になければなりません。例外がトリガされない場合、コードは通常どおり続行します。 しかし、例外がトリガされた場合、例外がスローされます
  2. Throw - これは、例外をトリガーする方法です。それぞれの "throw" には少なくとも1つの "catch" がなければなりません
  3. Catch - "catch" ブロックは例外を取得し、例外情報を含むオブジェクトを作成します

妥当なコードで例外をトリガーしてみましょう:

<?php
//create function with an exception
function checkNum($number) {
  if($number>1) {
    throw new Exception("Value must be 1 or below");
  }
  return true;
}

//trigger exception in a "try" block
try {
  checkNum(2);
  //If the exception is thrown, this text will not be shown
  echo 'If you see this, the number is 1 or below';
}

//catch exception
catch(Exception $e) {
  echo 'Message: ' .$e->getMessage();
}
?>

上のコードは次のようなエラーになります:

Message: Value must be 1 or below

例の説明:

上のコードは例外をスローしてキャッチします:

  1. checkNum()関数を作成します。数値が1より大きいかどうかを調べます。値が1より大きい場合は、例外をスローします。
  2. checkNum()関数は、"try"ブロックの中からで呼び出されます
  3. 関数内の例外がスローされます
  4. "catch" ブロックは例外を取得し、例外情報を含むオブジェクト($e)を作成します
  5. 例外からのエラーメッセージは、例外オブジェクトから$e->getMessage()を呼び出すことによってエコーします

しかし、"すべてのスローにはキャッチがなければならない"とのルールを回避する方法の1つは、トップレベルの例外ハンドラに すり抜けるエラーを処理を設定することです。 (However, one way to get around the "every throw must have a catch" rule is to set a top level exception handler to handle errors that slip through.)


カスタム例外クラスの作成

カスタム例外ハンドラを作成するには、PHPで例外が発生したときに呼び出すことのできる、特別なクラスを作成する必要があります。 クラスは例外クラスの拡張でなければなりません。

カスタム例外クラスは、PHPの例外クラスからプロパティを継承すると共に、カスタム関数を追加することが可能です。

例外クラスを作成します:

<?php
class customException extends Exception {
  public function errorMessage() {
    //error message
    $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
    .': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';
    return $errorMsg;
  }
}

$email = "someone@example...com";

try {
  //check if
  if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
    //throw exception if email is not valid
    throw new customException($email);
  }
}

catch (customException $e) {
  //display custom message
  echo $e->errorMessage();
}
?>

新しいクラスは、errorMessage()関数を追加した古い例外クラスのコピーです。 これは古いクラスのコピーであり、古いクラスのプロパティとメソッドを継承しているため、getLine()やgetFile()、 getMessage()などの例外クラスメソッドを使用することができます。

例の説明:

c上のコードは例外をスローし、それをカスタム例外クラスでキャッチします:

  1. customException()クラスは、古い例外クラスの拡張として作成します。この方式は、古い例外クラスのすべてのメソッドとプロパティを継承します
  2. errorMessage()関数を作成します。この関数は、メールアドレスが無効な場合に、エラーメッセージを返します
  3. $email変数には、有効ではないメールアドレスの文字列を設定します
  4. "try" ブロックが実行され、メールアドレスが無効であるため例外がスローされます
  5. "catch" ブロックは例外をキャッチし、エラーメッセージを表示します

複数の例外

スクリプトで複数の条件をチェックし複数の例外を使用することが可能です。.

いくつかのif..elseブロック、switch、または複数の例外をネストすることができます。 これらの例外は、異なる例外クラスを使用し、異なるエラーメッセージを返すことができます:

<?php
class customException extends Exception {
  public function errorMessage() {
    //error message
    $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
    .': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';
    return $errorMsg;
  }
}

$email = "someone@example.com";

try {
  //check if
  if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
    //throw exception if email is not valid
    throw new customException($email);
  }
  //check for "example" in mail address
  if(strpos($email, "example") !== FALSE) {
    throw new Exception("$email is an example e-mail");
  }
}

catch (customException $e) {
  echo $e->errorMessage();
}

catch(Exception $e) {
  echo $e->getMessage();
}
?>

例の説明:

上のコードは2つの条件をテストし、いずれかの条件が満たされない場合は例外をスローします:

  1. customException()クラスは、古い例外クラスの拡張として作成します。この方式では、古い例外クラスのすべてのメソッドとプロパティを継承します
  2. errorMessage()関数を作成します。この関数は、メールアドレスが無効な場合に、エラーメッセージを返します
  3. $email変数には、有効なメールアドレスですが、文字列 "example"を含む文字列を設定します
  4. "try" ブロックが実行されますが、最初の条件では例外がスローされません
  5. メールアドレスに、文字列 "example"が含まれているため、2番目の条件で例外が発生します"
  6. "catch" ブロックは例外をキャッチし、エラーメッセージを表示します

スローされた例外が class customException で、customException catch がなく、基本的な例外の catch しかなかった場合、その例外はそこで処理されます。


例外の再スロー

時には、例外がスローされたときに、標準的な方法とは異なる方法で処理したい場合もあります。"catch"ブロック内で例外を2回スローすることは可能です。

スクリプトは、システムエラーをユーザから隠すべきです。システムエラーは、コーダにとって重要であるかもしれませんが、 ユーザにとっては何の関心もありません。ユーザにとって使いやすいものにするために、ユーザーフレンドリーなメッセージで例外を再スローすることができます:

<?php
class customException extends Exception {
  public function errorMessage() {
    //error message
    $errorMsg = $this->getMessage().' is not a valid E-Mail address.';
    return $errorMsg;
  }
}

$email = "someone@example.com";

try {
  try {
    //check for "example" in mail address
    if(strpos($email, "example") !== FALSE) {
      //throw exception if email is not valid
      throw new Exception($email);
    }
  }
  catch(Exception $e) {
    //re-throw exception
    throw new customException($email);
  }
}

catch (customException $e) {
  //display custom message
  echo $e->errorMessage();
}
?>

例の説明:

上のコードは、メールアドレスに "example"という文字列が含まれているかどうかを調べ、含まれている場合は、例外を再スローします:

  1. customException()クラスは、古い例外クラスの拡張として作成します。この方式では、古い例外クラスのすべてのメソッドとプロパティを継承します
  2. errorMessage()関数を作成します。この関数は、メールアドレスが無効な場合に、エラーメッセージを返します
  3. $email変数には、有効なメールアドレスですが、文字列 "example"を含む文字列を設定します
  4. "try"ブロックには、例外を再スローするための別の "try"ブロックが含まれています
  5. メールアドレスに文字列 "example"が含まれているため、例外が発生します
  6. "catch" ブロックは例外をキャッチし、"customException"に再スローします
  7. "customException"がキャッチし、エラーメッセージを表示します

例外が現在の "try"ブロックでキャッチできない場合、"上位レベル"のcatchブロックを検索します。


トップレベル例外ハンドラの設定

set_exception_handler()関数は、キャッチされないすべての例外を処理するユーザ定義関数を設定します。

<?php
function myException($exception) {
  echo "<b>Exception:</b> " . $exception->getMessage();
}

set_exception_handler('myException');

throw new Exception('Uncaught Exception occurred');
?>

output of the code above should be something like this:

Exception: Uncaught Exception occurred

上のコードには、"catch"ブロックはありませんでしたので、代わりに、トップレベル例外ハンドラがトリガされました。 この関数は、キャッチされない例外をキャッチするために使用します。


例外のルール

単純なルール:何かをスローするなら、それをキャッチしなければなりません。


❮ 前章へ 次章へ ❯