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
キーワードによって、呼び出し元にスローできる