PHP - OOP - 7. 例外(Exception) - 2/2
引き続き例外について学習していきましょう。ここではスローされた Exception インスタンスをキャッチ(捕捉)して処理を継続する方法を学習します。
例外処理(try - catch文)の記述
これまでに学習してきたとおり Exception インスタンスは throw キーワードによってスローできます。たとえば MyClass クラスの myMethod の中で引数 $x が空文字の場合に Excetpion インスタンスをスローするとしましょう。
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 インスタンスはメソッドの呼び出し元で try - catch 文を実装することでキャッチできます。
require_once("MyClass.php");
try {
$myClass = new MyClass("Hello");
$myClass->myMethod(""); #=> throw Exception
} catch (Exception $e) {
echo "Catch exception." . PHP_EOL;
}
try - catch 文はスローされた例外をキャッチするために使用します。
try {
// 例外の発生する可能性のある処理
} catch (キャッチ対象の例外クラス名 変数名) {
// 例外発生時の処理
}
try の処理ブロック {} の中で例外がスローされると後の catch の処理ブロック {} に処理が移ります。このとき catch 引数 (Exception $e) にはスローされた Exception インスタンスが代入されます。このプログラムを実行すると画面に Catch exception. と出力されます。
try - catch 文の動作イメージを使うために次のプログラムの実行結果も考えてみましょう。
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"); と変更した場合はどうでしょうか。
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("GreatCalc.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ブロックの定義にはキャッチ対象の例外クラス名と、発生した例外インスタンスを格納する変数を定義する