PHP - OOP - 10. Exceptionクラスの継承

引き続き継承について学習していきましょう。ここでは Exception クラスを継承して例外クラスの作成に取り組みます。

Exceptionクラスの継承

これまでに学習してきたようにPHPには例外を表す Exception クラスが用意されています。この Exception クラスを継承して独自の例外クラスを定義できます。次のプログラムを MyException.php ファイルとして作成してみましょう。

<?php
class MyException extends Exception
{

}

ここでは MyException という名前で例外クラスを定義しています。クラスの中では新たなプロパティやメソッドを追加していませんが、このようなプログラムも問題なく動作します。 MyException クラスも Exception 型のインスタンスと言えるので throw キーワードでスロー可能です。 MySubClass.php ファイルの myMethod メソッドを修正してみましょう。

<?php
require_once("MyClass.php");
require_once("MyException.php");

class MySubClass extends MyClass
{
    public function myMethod($x)
    {
        if ($x == "") {
            $e = new MyException();
            throw $e;
        }
        echo "Override!" . PHP_EOL;
    }

    public function myMethod2()
    {
        echo "Hello World!" . PHP_EOL;
    }
}

myMethod メソッドにおいては引数 $x が空文字だった場合に MyException インスタンスをスローするように実装しています。

このようにスローした独自の例外クラス( Exception クラスのサブクラス)も catch ブロックに指定できます。my_class_runner.php ファイルを修正してみましょう。

<?php
require_once("MySubClass.php");

try {
    $myClass = new MySubClass("Hello");
    $myClass->myMethod(""); #=> throw MyException
} catch (MyException $e) {
    echo "Catch exception." . PHP_EOL;
}

プログラムを実行すると画面に Catch exception. と表示されるでしょう。このように catch (MyException $e) と実装することで MyException インスタンスだけをキャッチするようになります。

以前のような catch (Exception $e) という実装はあまり好ましいものではありません。この場合 Exception クラスおよび、そのサブクラスのインスタンスもすべてキャッチしてしまうからです。開発の現場では独自の例外クラスを作成するなどして、キャッチ対象の例外クラスを具体的に指定することが一般的です。

PHPプログラムの開発(計算機例外クラス)

ここでは SimpleCalc クラスの divide メソッドにおいて、 0 による除算が発生した際に、独自の例外クラスである計算機例外( CalcException )をスローするように変更します。

まずは計算機例外クラス( CalcException.php )を作成します。

<?php
class CalcException extends Exception
{
    const DIVIDE_BY_ZERO = "Divide by 0.";
}

CalcException クラスでは extends キーワードを指定してスーパークラスに Exception クラスを指定しています。また class 定義時に const キーワードによってクラス定数を定義できます。クラス定数は通常のプロパティのように値を変更することができません。変更のないデータを定義する際に利用します。またクラス定数はアクセス権が public となります。

次に SimpleCalc クラスの divide メソッドを修正します。

<?php
require_once("CalcException.php");

class SimpleCalc
{
    // ...省略

    public function divide($x)
    {
        if ($x == 0) {
            $e = new CalcException(CalcException::DIVIDE_BY_ZERO);
            throw $e;
        }
        $this->number = $this->number / $x;
    }

    // ...省略
}

ここでは CalcException クラスのコンストラクタ引数に CalcException::DIVIDE_BY_ZERO を指定しています。このようにクラス定数にアクセスするには :: スコープ定義演算子(ダブルコロン演算子)を指定します。

さいごに実行プログラム( calc_runner.php )を修正します。

<?php
require_once("GreatCalc.php");
require_once("CalcException.php");

try {
    $calc = new GreatCalc(10);

    $calc->divide(0);

    $calc->show();
} catch (CalcException $e) {
    echo "CalcException: " . $e->getMessage() . PHP_EOL;
}

ここでは catch ブロックでキャッチ対象の例外クラスに CalcException を指定している点を確認しておきましょう。作成した例外クラスはこのように catch ブロックに指定可能です。

それではコマンドラインからプログラムを実行してみましょう。

$ php calc_runner.php
CalcException: Divide by 0.

実行結果から divide メソッドによってスローされた CalcExceptioncatch ブロックで適切に処理できているのがわかります。

まとめ

  • PHPの定義済みクラスを継承して新たなクラスを作成できる
  • ユーザー例外 Exception クラスを継承して独自の例外クラスを定義できる
  • 例外処理( try - catch 文)の catch ブロックの引数に定義した例外クラスを指定できる