PHP - OOP - 8. 例外処理(try - catch文)
引き続き例外について学習していきましょう。ここではスローされた例外( Exception
インスタンス)をキャッチ(捕捉)して処理を継続する方法(try - catch文)を学習します。
例外処理(try - catch文)の記述
これまでに学習してきたとおり、プログラムにおける例外を意味する Exception
インスタンスは throw
キーワードによってスローできます。以前に作成した MyClass
クラスの myMethod
では、引数 $x
が空文字の場合に Excetpion
インスタンスをスローしています。
<?php
class MyClass
{
public $myProperty;
public function __construct($value)
{
$this->myProperty = $value;
}
public function myMethod($x)
{
if ($x == "") {
$e = new Exception("Invalid argument.");
throw $e;
}
echo $this->myProperty . " " . $x;
}
}
この myMethod
からスローされた Exception
インスタンスはメソッドの呼び出し元( my_class_runner.php
)において try - catch
文を実装することでキャッチできます。
<?php
require_once("MyClass.php");
try {
$myClass = new MyClass("Hello");
$myClass->myMethod(""); #=> throw Exception
} catch (Exception $e) {
echo "Catch exception." . PHP_EOL; # => Catch exception.
echo $e->getMessage() . PHP_EOL; #=> Invalid argument.
}
try - catch
文はスローされた例外をキャッチするために使用します。try - catch
文の構文について整理しておきましょう。
try {
// 例外の発生する可能性のある処理
} catch (キャッチ対象の例外クラス名 変数名) {
// 例外発生時の処理
}
try
の処理ブロック {}
の中で例外がスローされると後の catch
の処理ブロック {}
に処理が移ります。このとき catch
ブロックの引数 (Exception $e)
にはスローされた Exception
インスタンスが代入されます。また catch
ブロックの中で以下のように実装しています。
echo "Catch exception." . PHP_EOL; # => Catch exception.
echo $e->getMessage() . PHP_EOL; #=> Invalid argument.
先頭の echo
命令で Catch exception.
と改行コード付きで出力しています。それから $e->getMessage()
の部分ではキャッチした Exception
インスタンスに対して getMessage
というメソッドを呼び出しています。Exception
クラスはコンスタント引数で設定したメッセージを getMessage
メソッドで取得できるようになっています。そのため画面には Invalid argument.
と出力されます。
Exception
クラスはPHPの中であらかじめ用意されているクラスです。PHPのマニュアルページを見るとコンストラクタの定義やメソッドの定義を確認できます。PHPマニュアル - Exception
try - catch 文の挙動について
try - catch
文の動作イメージを使うために次のプログラム( my_class_runner.php
)の実行結果も考えてみましょう。
<?php
require_once("MyClass.php");
echo "1";
try {
$myClass = new MyClass("Hello");
$myClass->myMethod(""); #=> throw Exception
echo "2";
} catch (Exception $e) {
echo "3";
}
echo "4";
このプログラムでは $myClass->myMethod("");
の呼び出しで Exception
インスタンスがスローされます。そのため処理は catch
ブロックに移るため、 echo "2";
は実行されません。この場合の実行結果は 134
となります。
また $myClass->myMethod("Andy");
と変更した場合はどうでしょうか。
<?php
require_once("MyClass.php");
echo "1";
try {
$myClass = new MyClass("Hello");
$myClass->myMethod("Andy"); #=> Hello Andy
echo "2";
} catch (Exception $e) {
echo "3";
}
echo "4";
この場合は Exception
インスタンスはスローされないため実行結果は 1Hello Andy24
となります。
PHPプログラムの開発(try - catch文)
それでは計算機プログラムの呼び出し時に例外処理( try - catch
文)を実装してみましょう。まずは前節までの計算機クラス( SimpleCalc
クラス)を確認しておきましょう。
<?php
class SimpleCalc
{
// ...省略
public function divide($x)
{
if ($x == 0) {
$e = new Exception("Divide by 0.");
throw $e;
}
$this->number = $this->number / $x;
}
// ...省略
}
上記のように divide
メソッドで 0
による除算の発生時に Exception
インスタンスをスローしています。計算機クラス( SimpleCalc
クラス)に修正はありません。
次に実行プログラム( calc_runner.php
)を修正します。
<?php
require_once("SimpleCalc.php");
try {
$calc = new SimpleCalc();
$calc->add(10);
$calc->subtract(5);
$calc->multiply(10);
$calc->divide(0);
$calc->show();
} catch (Exception $e) {
echo "Exception: " . $e->getMessage() . PHP_EOL;
}
try
ブロックの中でスローされた Exception
インスタンスは catch
ブロックの引数( $e
)に代入されます。変数 $e
は Exception
クラスのインスタンスであるため、 Exception
クラスに定義されているメソッド( getMessage
メソッドなど)を呼び出すことができます。
Exception
クラスのgetMessage
メソッドは戻り値にコンストラクタで指定されたメッセージを返します。
それではターミナルからプログラムを実行してみましょう。
$ php calc_runner.php
Exception: Divide by 0.
実行結果からスローされた Exception
インスタンスを catch
ブロックで処理できているのがわかります。
参考:finallyブロックの使用
PHP5.5以降は try - catch
文に finally
ブロックを追加することもできます。
<?php
require_once("SimpleCalc.php");
try {
$calc = new SimpleCalc();
$calc->add(10);
$calc->subtract(5);
$calc->multiply(10);
$calc->divide(0);
$calc->show();
} catch (Exception $e) {
echo "Exception: " . $e->getMessage() . PHP_EOL;
} finally {
echo "finally" . PHP_EOL;
}
finally
ブロックは例外発生の有無に関わらず動作します。
まとめ
- スローされた例外(
Exception
クラスのインスタンス)はtry - catch
文で処理できる try
ブロックの中で例外が発生するとcatch
ブロックに処理が移るcatch
ブロックの定義にはキャッチ対象の例外クラス名と、発生した例外インスタンスを格納する変数を定義する