【PHP】try-catch解説

通常の実行時 (try ブロック内で例外が投げられなかった 場合) は、catch ブロック内は処理されず、それ以降から処理が続けられます。 
try-catchの使い方について、例を挙げて解説させていただきます。

### try-catch

#### try-catchブロックの役割

通常は、BLOCK1でtry-catch処理に必要な変数定義などの準備処理を入れます。
BLOCK2、つまりtryブロック。メイン処理に必要なロジックを入れて実行する。
BLOCK3、即ち、catchブロック。メイン処理に何が例外が発生したら、その情報が捕まれて、何かの対策にして、エンドユーザーに分かりやすくように、またはその情報を用いてログ出力して、開発者に原因調査に調べやすいように異常処理を入れます。
BLOCK4、tryブロックまたはcatchブロックの処理が終わったら、後続処理として実行する。ただ、状況により後続ロジックを処理しない場合があります。


```php5:try-catchブロック
/**
* BLOCK1
*   try-catchの前に何かのロジック処理
*
**/

try {
// try start
	/**
	* BLOCK2
	*   tryロジック処理
	*
	**/
// try end
} catch ( Exception $ex ) {
// catch start
	/**
	* BLOCK3
	*   catchロジック処理
	*
	**/
// catch end
}

/**
* BLOCK4
*   try-catchの後に何かのロジック処理
**/
```

#### サンプルから説明

例え、ピープルというテーブルに一行インサートして、何が発生したら、そのエラー情報をキャッチしてログに出力する処理を実装しましょう。
上記のブロックの役割を参考にして、単純に `例1-①` の書き方でいいではないでしょうか。

```php5:例1-①
/* 例1-① */
$PeopleModel = new PeopleInfoModel();
try {
	$insert = $PeopleModel->insertOneRecord ( $conn, $pno, $pname, $mail, $address);
	// 後続処理が続く
} catch ( Exception $ex ) {
	LogUtil::logError ( Const::DEF_LOG_DATABASE, $ex->getMessage () );
	// 後続処理が続く
}
// 後続処理

```

##### **後続処理中断**

ただし、システム内にエラーが発生しているのに、後続処理が続くのはまずくない？
継続処理すると、後ろの処理が全部通ってしまい、途中でエラーが発生しても、最後まで正常終了となる場合があります。
API系やBatch系で、途中で何かしらのエラーが起こしたら、その場で処理が止まって、エラーで返却するのほうが多いです。

```php5:例1-②
/* 例1-② */
$PeopleModel = new PeopleInfoModel();
try {
	$insert = $PeopleModel->insertOneRecord ( $conn, $pno, $pname, $mail, $address);
	// 後続処理が続く
} catch ( Exception $ex ) {
	return FALSE;
	// 後続処理は中断
}
// 後続処理

```


##### **追跡ログ出力**


catch自身はエラー情報が`$ex`に揃えているが、ログ出力処理がないと、自動的に出せないので、`$ex->getMessage () `を用いて、ちゃんとエラー情報を明確的に出しましょう。
そしたら、原因調査や追跡が楽になるでしょう。


```php5:例1-③
/* 例1-③ */
$PeopleModel = new PeopleInfoModel();
$insert = FALSE;
try {
	$insert = $PeopleModel->insertOneRecord ( $conn, $pno, $pname, $mail, $address);
	// 後続処理が続く
} catch ( Exception $ex ) {
	LogUtil::logError ( Const::DEF_LOG_DATABASE, $ex->getMessage () );
	return FALSE;
	// DBエラーログを出力して、後続処理は中断
}
// 後続処理

```

**Tip**
繰り返し文にtry-catchがある場合、何がのエラーが起こしたら、returnではなくて、繰り返し処理を継続するのかを決めてから、breakやcontinueを用って制御しましょう。


##### **処理パターンのこだわり**

上記は、主にcatchブロックの説明ですが、tryブロックだとそれだけで十分ではありません。
なぜなら、`$insert`は初期値の定義があるが、tryブロックでの実行結果は`TRUE`で返却されるのははっきりできないので、もしも`FALSE`のままでしたら、tryブロックで正常として終了してしまい、また後続処理が続くことになります。
だから、tryブロックで厳密に`$insert`の実行結果をチェックして、処理継続するかを決まります。

```php5:例2-①
/* 例2-① */
$PeopleModel = new PeopleInfoModel();
$insert = FALSE;
try {
	$insert = $PeopleModel->insertOneRecord ( $conn, $pno, $pname, $mail, $address);
	if (!$insert) {
		LogUtil::logError ( Const::DEF_LOG_DATABASE, "テーブル登録失敗 pno[" . $pno . "]" );
		return FALSE;
		// DBエラーログを出力して、後続処理は中断
	}
	// 後続処理が続く
} catch ( Exception $ex ) {
	LogUtil::logError ( Const::DEF_LOG_DATABASE, $ex->getMessage () );
	return FALSE;
	// DBエラーログを出力して、後続処理は中断
}
// 後続処理

```

わざわざtryブロックとcatchブロックの中で実行結果チェック処理を２回で書くのはめんどくさいと思っている人にとって、もっと簡潔に書くと、継続処理の制御をまとめていいではないか。

```php5:例2-②
/* 例2-② */
$PeopleModel = new PeopleInfoModel();
$insert = FALSE;
try {
	$insert = $PeopleModel->insertOneRecord ( $conn, $pno, $pname, $mail, $address);
} catch ( Exception $ex ) {
	LogUtil::logError ( Const::DEF_LOG_DATABASE, $ex->getMessage () );
}
if (!$insert) {
	LogUtil::logError ( Const::DEF_LOG_DATABASE, "テーブル登録失敗 pno[" . $pno . "]" );
	return FALSE;
	// DBエラーログを出力して、後続処理は中断
}
// 後続処理

```

**Tip**
PHPは厳密な言語ではないので、自由に楽に書いていいと思い込んでしまったら、いつのタイミングでそれの弱点によるシステム障害が発生したら、大変な事になってしまいます。
いいコーディング習慣を身に付けるのはいつでも違いない。

*参考：*
[例外(exceptions)](http://php.net/manual/ja/language.exceptions.php)


`---I Love PHP (｡･ω･｡)ﾉ♡`