カテゴリー:
制御構造
閲覧数:796 配信日:2010-05-22 10:16
投げない
例外を投げていない
・例外を「スロウ(投げる)」していないため、エラーが起こっても「トライ」が全部実行され「例外処理」も実行されない、無意味なサンプル
※「例外処理」は、「例外」が「スロウ(投げる)」されてはじめて実行される
echo "--- 例外 テスト ---\n\n";//①
try{
echo "→→→ try 開始 →→→\n\n";//②
#引数が不正な関数コール(「Warning」警告)
//substr();
echo "←←← try 終了 ←←←\n\n";
}catch(Exception $e){
echo "****** catch ******\n\n";
}
echo "--- 例外 テスト ---";
・結果
--- 例外 テスト ---
→→→ try 開始 →→→
←←← try 終了 ←←←
--- 例外 テスト ---
→→→ try 開始 →→→
←←← try 終了 ←←←
--- 例外 テスト ---
投げる
「例外」を「スロウ(投げる)」して「例外処理」を実行するサンプル
echo "--- 例外 テスト ---\n\n";//①
try{
echo "→→→ try 開始 →→→\n\n";//②
echo "- 例外が投げられました。-\n\n";
throw new Exception("例外が投げられました。");//③「try」ブロックの処理はこの一文が実行された時点で中断。「Exception」クラスのインスタンスを生成し、コンストラクタに「"例外が投げられました。"」という文字列を渡している
echo "←←← try 終了 ←←←\n\n";
}catch(Exception $e){//④投げられた「例外」を「キャッチ」。「変数$e」は必ず「Exception」クラスのインスタンスが渡されることを想定した「catch」の引数。つまり、「throw文」によって投げられた「Exception」クラスのオブジェクトは「変数$e」に引数として代入され、キャッチブロック内で利用されることになる。
echo "****** catch ******\n\n";
echo '$e->getMessage() : ', $e->getMessage(), "\n\n";//キャッチブロック内の「例外処理」を実行
//echo "\$e : \n", $e, "\n\n";
}
echo "--- 例外 テスト ---\n\n";//
・結果
--- 例外 テスト ---
→→→ try 開始 →→→
- 例外が投げられました。-
****** catch ******
$e->getMessage() : 例外が投げられました。
--- 例外 テスト ---
→→→ try 開始 →→→
- 例外が投げられました。-
****** catch ******
$e->getMessage() : 例外が投げられました。
--- 例外 テスト ---
投げる順番
最初の「throw文」が実行される前に、コンストラクタ内の「throw文」が実行される例
class NotException{}
class Ex1 extends Exception{
public function __construct($message = NULL, $code = 0){
parent::__construct($message, $code);
//throw new NotException; //「Not例外オブジェクト」を生成して投げようとしている//Fatal error: Exceptions must be valid objects derived from the Exception base class
}
}
try{
throw new Ex1;//①「例外オブジェクト」を生成して投げようとしている
}catch(Exception $e){
}
0除算
エラーを発生させ、try~catchで例外を補足している例
・tryブロック内の処理でdivision関数の第2引数を0にして呼び出した際に例外が発生し、Exceptionクラスのオブジェクトが投げられる。続いて、「例外クラス名でExceptionを指定したcatchブロック」で例外が捕捉され、処理が行われていることが確認できる。なお、tryブロック内で例外が発生しなかった場合は、catchブロックの処理は行われない
function division($arg1, $arg2)
{
if ($arg2 === 0) {
throw new Exception('ゼロ除算はできません。<br>');
}
$answer = $arg1 / $arg2;
return $answer;
}
echo 'try catch start<br>', PHP_EOL;//定数 ソース上で改行
try {
echo 'try start<br>', PHP_EOL;
echo division(10, 2)."<br>", PHP_EOL;
echo division(10, 0), PHP_EOL;
echo 'try end<br>', PHP_EOL;
} catch (Exception $e) {
echo 'catch start<br>', PHP_EOL;
echo $e->getMessage(), PHP_EOL;
echo "例外コード:" . $e->getCode()."<br>", PHP_EOL;
echo "行番号:" . $e->getLine()."<br>", PHP_EOL;
echo "<pre>バックトレース:<br>";
p( $e->getTrace( ) );
echo "</pre>";
echo 'catch end<br>', PHP_EOL;
}
echo 'try catch end<br>例外処理後、スクリプト継続', PHP_EOL;
/* 出力:
try catch start
try start
5
catch start
ゼロ除算はできません。
例外コード:0
行番号:19
バックトレース:
Array
(
[0] => Array
(
[file] => /○○/PHPStyleNote/basic/exception/7.php
[line] => 30
[function] => division
[args] => Array
(
[0] => 10
[1] => 0
)
)
)
catch end
try catch end
例外処理後、スクリプト継続
*/
簡易クラス
class Calc
{
public static function division($int1, $int2){
try {
if ($int2 == 0) {
throw new Exception('0で割ろうとしました');
}
$answer = $int1 / $int2;
echo $answer . "
";
echo '割り算が終了しました' . "
";
} catch (Exception $e) {
echo $e->getMessage() . "
";
echo '割り算が異常終了しました' . "
";
}
}
}
Calc::division(10, 2);
Calc::division(10, 0);
・結果
5
割り算が終了しました
0で割ろうとしました
割り算が異常終了しました
割り算が終了しました
0で割ろうとしました
割り算が異常終了しました
場合分け項目を増加
function division($num1, $num2){//②
try{
if($num2 === 0)//「比較演算子===」等しい(型も同じ) ⑩
throw new Exception('「0」で割ることは出来ません。');
else if(!is_numeric($num1) || !is_numeric($num2))//「論理和||」いずれかのオペランドが「真」なら「true」 を返す
throw new Exception('値が不正です。');//⑥
return $num1 / $num2;//③ ⑧0÷10=0 「0を割る」は成立する。
}catch(Exception $e){
return $e->getMessage();
}
}
echo division(10, 2), "\n";//①④
echo division(10, ""), "\n";//⑤
echo division(0, 10), "\n";//⑦
echo division(10, 0), "\n";//⑨
・結果
5
値が不正です。
0
「0」で割ることは出来ません。
値が不正です。
0
「0」で割ることは出来ません。
例外ごとのクラス作成
class DivisionEx extends Exception{}//Exception」クラスを継承した「DivisionException」クラスを定義。“割算における「例外」”
class DivisionIsZeroEx extends DivisionEx{//「DivisionEx」クラスを継承した「DivisionIsZeroEx」クラスを定義。“分母が「0」であるという「例外」”
protected $message = '「0」で割ることは出来ません。';
}
class DivisionWrongValueEx extends DivisionEx{//「DivisionEx」クラスを継承した「DivisionWrongValueEx」クラスを定義。“値が不正であるという「例外」”
protected $message = '値が不正です。';//⑮
}
class Division{//割算を行うためのクラス。コンストラクタに渡された2つの値をチェックし、問題があれば「例外」を投げ、問題がなければ(「例外」が投げられていなければ)演算結果をプロパティに保存
private $result;//⑤⑳
public function __construct($num1, $num2){
if($num2 === 0)
throw new DivisionIsZeroEx;
else if(!is_numeric($num1) || !is_numeric($num2))
throw new DivisionWrongValueEx;//⑬
$this->result = $num1 / $num2;//④⑲
}
public function getResult(){//⑦
return $this->result;
}
}
function division($num1, $num2){//②⑪⑰
try{//投げる元はココ
$division = new Division($num1, $num2);//③⑫⑱
return $division->getResult();//⑥⑧
}catch(DivisionEx $e){//ここでキャッチ
return $e->getMessage();//⑭
}
}
echo division(10, 2), "\n";//①⑨
echo division(10, ""), "\n";//⑩
echo division(0, 10), "\n";//⑯
echo division(10, 0), "\n";
・結果
5
値が不正です。
0
「0」で割ることは出来ません。
値が不正です。
0
「0」で割ることは出来ません。
ファイルオープン
処理基点となるスクリプトをtry~catchすることで、全ての例外をそこで捕まえる例
class File
{
public static function read($path)
{
if (false == file_exists($path)) {
throw new Exception('ファイルが存在しません');
}
$fp = @fopen($path, 'r');
if (false === $fp) {
throw new Exception('ファイルのオープンに失敗しました');
}
$data = @stream_get_contents($fp);
if (false === $fp) {
throw new Exception('ファイルの読込に失敗しました');
}
return $data;
}
}
class StringViewer
{
public function display($path)
{
try {
$data = File::read($path);
echo $data;
} catch (Exception $e) {
die($e->getMessage());
}
}
}
$viewer = new StringViewer();
$viewer->display('C:/aaa.txt');
・結果
ファイルが存在しません