PHP - OOP - 7. 例外(Exceptionクラス)
ここからは例外( Exception )について学習します。例外( Exception )とはプログラムの予期せぬ事態を通知する仕組みです。例外とよく似た言葉にエラーがありますが、一般的に、PHPのエラーとは復旧することのできない致命的な問題を意味します。一方の例外は想定外の事態を意味しますが、適切に対処することで処理を継続することも可能となります。

例外の仕組み
PHPには例外を扱うためのクラスとして Exception クラスが用意されています。 Exception クラスのインスタンスを生成することで、プログラムの中で例外を生成できます。
$e = new Exception();
また Exception クラスには例外メッセージを引数にとるコンストラクタも用意されているので、次のように Exception インスタンスを生成できます。
$e = new Exception("Exctption message.");
生成した例外インスタンスは throw キーワードによって通知できます。
$e = new Exception("Exctption message.");
throw $e;
PHPでは例外を通知することを「例外をスローする」と言います。スローされた例外インスタンスは後で紹介する try - catch 構文によって処理できるようになっています。
まずは例外をスローする方法を確認しましょう。以前に作成している MyClass.php ファイルの myMethod メソッドを次のように修正します。
<?php
class MyClass
{
private $myProperty;
public function __construct($myProperty)
{
$this->myProperty = $myProperty;
}
public function myMethod($x)
{
if ($x === "") {
$e = new Exception("Invalid argument.");
throw $e;
}
echo $this->myProperty . " " . $x . PHP_EOL;
}
public function setMyProperty($myProperty)
{
$this->myProperty = $myProperty;
}
public function getMyProperty()
{
return $this->myProperty;
}
}
ここでは myMethod の引数 $x が "" から文字だった場合に Exception インスタンスをスローするように実装しています。メソッドの中で throw キーワードによって例外がスローされるとメソッドの処理はそこで終了し、メソッドの呼び出し元に例外がスローされるようになっています。
それでは実際に例外が発生する(スローされる)様子を見てみましょう。my_class_runner.php ファイルを次のように修正します。
<?php
require_once("MyClass.php");
$myClass = new MyClass("Hello");
$myClass->myMethod(""); #=> throw Exception
プログラムを実行すると $myClass->myMethod("") の呼び出しによって Exception インスタンスがスローされます。次のような結果が出力されるでしょう。
$ php my_class_runner.php
Fatal error: Uncaught Exception: Invalid argument. in /home/ec2-user/environment/MyClass.php:14
Stack trace:
#0 /home/ec2-user/environment/my_class_runner.php(5): MyClass->myMethod('')
#1 {main}
thrown in /home/ec2-user/environment/MyClass.php on line 14
ここでは my_class_runner.php ファイルと MyClass.php ファイルの関係を整理しておきましょう。

my_class_runner.php ファイルの中で MyClass 型のインスタンスに対して myMethod メソッドを呼び出しています。このとき引数に "" 空文字を指定しているので、MyClass クラスの myMedhod の内部で例外(Exception 型のインスタンス)がスローされます。
スローされた例外は次節で紹介する
try - catch構文によって処理できるようになっています。
PHPプログラムの開発(0による除算)

それでは簡単な計算機クラス( SimpleCalc.php )を題材に例外について考えてみましょう。これまでに加算処理を行う add メソッドを実装しているので、ここでは新たに以下の3つのメソッドを追加して四則演算を完成させます。
subtractメソッド(減算)multiplyメソッド(乗算)divideメソッド(除算)
<?php
class SimpleCalc
{
// 省略
public function add($x)
{
$this->number = $this->number + $x;
}
public function subtract($x)
{
$this->number = $this->number - $x;
}
public function multiply($x)
{
$this->number = $this->number * $x;
}
public function divide($x)
{
$this->number = $this->number / $x;
}
public function show()
{
echo $this->number . PHP_EOL;
}
}
ここでは除算を行う divide メソッドに注目してください。 divide メソッドの引数に 0 を指定すると 、 0 による除算が発生します。このような演算は行えないため、PHPは実行時に Warning メッセージを出力します。
実行プログラム( calc_runner.php )を以下のように修正してみましょう。
<?php
require_once("SimpleCalc.php");
$calc = new SimpleCalc();
$calc->add(10);
$calc->subtract(5);
$calc->multiply(10);
$calc->divide(0); // Warning!
$calc->show();
ここでは $calc->divide(0) と呼び出している部分で 0 による除算が発生し、戻り値には無限を表す定数 INF が返却されます。ターミナルからプログラムを実行してみましょう。
$ php calc_runner.php
Warning: Division by zero in /home/ec2-user/environment/SimpleCalc.php on line 40
INF
PHPにおける Warning メッセージはエラーとも例外とも異なります。Warning メッセージは出力されるものの、後続の処理は継続されるようになっています。
PHPプログラムの開発(例外の生成)
次に計算機クラス( SimpleCalc クラス)の除算を行う divide メソッドを修正して、 0 による除算が発生した場合は演算を行う前に例外( Exception インスタンス)をスローするように修正します。
<?php
class SimpleCalc
{
// ...省略
public function divide($x)
{
if ($x == 0) {
$e = new Exception("Divide by 0.");
throw $e;
}
$this->number = $this->number / $x;
}
// ...省略
}
divide メソッドでは引数 $x の値が 0 の場合 Exception インスタンスを生成して、 throw キーワードによって例外をスローしています。 throw キーワードは return キーワードのように、呼び出された時点でメソッドの処理を終了します。
計算機クラス( SimpleCalc.php )を修正したので、もう一度、実行プログラム( calc_runner.php )を動かしてみましょう。
$ php calc_runner.php
Fatal error: Uncaught Exception: Divide by 0. in /home/ec2-user/environment/SimpleCalc.php:39
Stack trace:
#0 /home/ec2-user/environment/calc_runner.php(9): SimpleCalc->divide(0)
#1 {main}
thrown in /home/ec2-user/environment/SimpleCalc.php on line 39
実行結果を見ると先ほどのように Warning メッセージが出力されていないのがわかります。その代わりに Fatal error: Divide by 0. というメッセージを確認できます。これはPHPの Fatal error (致命的なエラー)が発生したことを意味しており、その原因として Exception がキャッチされなかった( Uncaught Exception )と説明が続きます。またメッセージの後には例外の発生箇所やスタックトレースの出力が確認できます。
ここでは例外をスローする方法として、 Exception クラスと throw キーワードについて取り上げました。以降はここでスローされた例外を適切に処理する方法を解説します。
参考:Exceptionクラス
Exception クラスはPHPに標準で用意されている例外クラスです。 Exception クラスの詳細については PHPマニュアル - Exceptionを参照してください。
まとめ
- 例外(
Exception)とはプログラムの予期せぬ事態を通知する仕組み - PHPにはユーザー例外の基底クラスとして
Exceptionクラスが用意されている Exceptionクラス(および、そのサブクラス)のインスタンスはthrowキーワードによって、呼び出し元にスローできる