【PHP8.x】OutOfBoundsException::__construct()メソッドの使い方
__constructメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
『__constructメソッドは、OutOfBoundsExceptionオブジェクトを新しく作成し、初期化するために実行するメソッドです。』
OutOfBoundsExceptionは、配列や文字列などで、定義されていないインデックスやキーにアクセスしようとした際に発生する実行時エラーを表す例外です。このコンストラクタは、例外オブジェクトが生成される際に自動的に呼び出され、エラーに関する詳細な情報を設定します。引数として、エラーメッセージ、エラーコード、そして先行する例外(例外チェーン)の3つを受け取ることができます。第一引数のエラーメッセージは、なぜ例外が発生したのかを説明する文字列で、デバッグの際に役立ちます。第二引数のエラーコードは、例外の種類を識別するための整数値です。第三引数の先行する例外は、ある例外が別の例外を引き起こした場合に、その関連性を記録するために使用されます。これらの引数はすべて任意であり、省略することも可能です。通常、このメソッドは直接呼び出すのではなく、throw new OutOfBoundsException(...)のように例外をスローする際に暗黙的に使用され、例外オブジェクトを適切な状態で準備します。
構文(syntax)
1public __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
引数(parameters)
string $message = "", int $code = 0, ?Throwable $previous = null
- string $message: 例外発生時の詳細を示すエラーメッセージ
- int $code: 例外に割り当てられるエラーコード
- ?Throwable $previous: この例外の原因となった以前のスロー可能オブジェクト(null許容)
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
PHP 8: コンストラクタプロパティ昇格で例外を拡張する
1<?php 2 3/** 4 * PHP 8.0 の「コンストラクタプロパティ昇格」機能を示すためのカスタム例外クラス。 5 * 6 * この機能を使うと、コンストラクタの引数に public, protected, private 7 * を付けるだけで、プロパティの宣言と初期化を同時に行うことができます。 8 * 9 * この例では、OutOfBoundsException を継承し、 10 * 不正なインデックス値を保持する独自のプロパティを追加しています。 11 */ 12class InvalidIndexException extends OutOfBoundsException 13{ 14 /** 15 * クラスのコンストラクタ。 16 * 17 * @param public readonly int $invalidIndex アクセスしようとした無効なインデックス。 18 * `public readonly int $invalidIndex` と書くことで、 19 * 同名のプロパティが自動的に宣言され、引数の値が代入されます。 20 * @param string $message 例外メッセージ。 21 * @param int $code 例外コード。 22 * @param ?Throwable $previous 以前にスローされた例外。 23 */ 24 public function __construct( 25 public readonly int $invalidIndex, 26 string $message = "", 27 int $code = 0, 28 ?Throwable $previous = null 29 ) { 30 // メッセージが指定されていない場合は、デフォルトのメッセージを生成します。 31 if (empty($message)) { 32 $message = "無効なインデックス {$this->invalidIndex} にアクセスしようとしました。"; 33 } 34 35 // 親クラスである OutOfBoundsException のコンストラクタを呼び出します。 36 parent::__construct($message, $code, $previous); 37 } 38} 39 40// --- 実行コード --- 41 42// テスト用のデータ 43$data = ['apple', 'banana', 'cherry']; 44$targetIndex = 5; // 存在しないインデックス 45 46try { 47 // 配列の範囲外のインデックスにアクセスしようとします。 48 if (!isset($data[$targetIndex])) { 49 // カスタム例外をスローします。 50 // コンストラクタに渡した値が、自動的にプロパティにセットされます。 51 throw new InvalidIndexException($targetIndex); 52 } 53 echo $data[$targetIndex]; 54 55} catch (InvalidIndexException $e) { 56 // スローされたカスタム例外を捕捉します。 57 echo "エラー: " . $e->getMessage() . PHP_EOL; 58 // コンストラクタプロパティ昇格で定義されたプロパティにアクセスします。 59 echo "アクセスしようとしたインデックス: " . $e->invalidIndex . PHP_EOL; 60 echo "ファイル: " . $e->getFile() . "({$e->getLine()}行目)" . PHP_EOL; 61}
このサンプルコードは、PHP 8.0の新機能「コンストラクタプロパティ昇格」を利用し、標準のOutOfBoundsExceptionを拡張したカスタム例外クラスInvalidIndexExceptionを作成する例です。
OutOfBoundsExceptionのコンストラクタ__constructは、例外メッセージ、コード、そして先行する例外を引数として受け取ります。このサンプルでは、その機能を引き継ぎつつ、どのインデックスでエラーが発生したかを保持する独自のプロパティを追加しています。
InvalidIndexExceptionクラスのコンストラクタにあるpublic readonly int $invalidIndexという記述が、コンストラクタプロパティ昇格の機能です。このようにコンストラクタの引数にpublicなどの可視性修飾子を付けると、同名のプロパティがクラスに自動で宣言され、引数で渡された値がそのプロパティへ初期値として代入されます。これにより、クラス定義におけるプロパティ宣言と、コンストラクタ内での代入処理を省略でき、コードがより簡潔になります。
実行コードでは、配列の範囲外のインデックスを指定してInvalidIndexExceptionをスローし、catchブロックで捕捉しています。そして、$e->invalidIndexのように、コンストラクタプロパティ昇格によって自動的にセットされたプロパティに直接アクセスし、エラーの原因となった値を取得しています。
このコードはPHP 8.0からの「コンストラクタプロパティ昇格」という機能を利用しています。コンストラクタの引数に public などのアクセス修飾子を付けるだけで、プロパティの宣言と初期化を同時に行える便利な構文ですが、古いバージョンのPHPでは動作しない点に注意が必要です。また、readonly(PHP 8.1〜)を付けているため、プロパティ $invalidIndex には一度値が設定されると再代入できなくなり、意図しない変更を防げます。例外クラスを継承した際は、parent::__construct() を呼び出して親クラスの初期化処理を忘れずに行うことが重要です。これを忘れると、例外メッセージなどが正しく設定されない可能性があります。
PHPでカスタム例外のコンストラクタを定義する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * ユーザーが見つからない場合にスローされる、独自の例外クラス。 7 * 8 * PHPの組み込み例外である OutOfBoundsException を継承しています。 9 * これにより、範囲外アクセスという性質を持つ例外であることを示しています。 10 */ 11class UserNotFoundException extends OutOfBoundsException 12{ 13 /** 14 * 例外インスタンスを生成します。 15 * 16 * parent::__construct() を呼び出すことで、 17 * 親クラスである OutOfBoundsException のコンストラクタを呼び出し、 18 * 例外メッセージやコードを初期化しています。 19 * これが、継承におけるコンストラクタの一般的な使い方です。 20 * 21 * @param int $userId 検索されたユーザーID 22 * @param int $code 例外コード 23 * @param ?Throwable $previous 前の例外 24 */ 25 public function __construct(int $userId, int $code = 0, ?Throwable $previous = null) 26 { 27 // 親クラスのコンストラクタに渡すメッセージを組み立てる 28 $message = "指定されたIDのユーザーが見つかりません: {$userId}"; 29 30 // parentキーワードを使って親クラスのコンストラクタを呼び出す 31 parent::__construct($message, $code, $previous); 32 } 33} 34 35/** 36 * ユーザーデータを管理するクラス(例) 37 */ 38class UserRepository 39{ 40 private array $users = [ 41 1 => ['name' => 'Alice'], 42 2 => ['name' => 'Bob'], 43 ]; 44 45 /** 46 * IDによってユーザーを検索します。 47 * 48 * @param int $id ユーザーID 49 * @return array ユーザーデータ 50 * @throws UserNotFoundException ユーザーが存在しない場合 51 */ 52 public function findById(int $id): array 53 { 54 if (!isset($this->users[$id])) { 55 // ユーザーが存在しない場合、独自に定義した例外をスローする 56 throw new UserNotFoundException($id); 57 } 58 return $this->users[$id]; 59 } 60} 61 62// --- 実行コード --- 63$repository = new UserRepository(); 64 65try { 66 // 存在するユーザー(ID: 1)を取得する試み 67 $user = $repository->findById(1); 68 echo "ID:1 のユーザー名: " . $user['name'] . PHP_EOL; 69 70 // 存在しないユーザー(ID: 99)を取得する試み 71 echo "ID:99 のユーザーを検索します..." . PHP_EOL; 72 $repository->findById(99); 73} catch (UserNotFoundException $e) { 74 // UserNotFoundException がスローされた場合に、このブロックが実行される 75 echo "エラーが発生しました: " . $e->getMessage() . PHP_EOL; 76}
OutOfBoundsExceptionクラスの__constructメソッドは、この例外クラスのインスタンスが生成される際に自動的に呼び出されるコンストラクタです。配列のキーや文字列のオフセットなどが有効な範囲外にあることを示す例外オブジェクトを初期化する役割を持ちます。
このコンストラクタは3つの引数を取ります。第1引数$messageは例外の内容を説明する文字列、第2引数$codeは例外を識別するための整数コードです。第3引数$previousには、この例外がスローされる直前に発生した別の例外(Throwableオブジェクト)を指定でき、例外の連鎖を表現するために使用します。コンストラクタであるため、このメソッドに戻り値はありません。
サンプルコードでは、OutOfBoundsExceptionを継承した独自のUserNotFoundExceptionクラスを定義しています。そのクラスのコンストラクタ内では、まずユーザーIDを含んだ独自の例外メッセージを生成しています。次に、parent::__construct()という形式で親クラスであるOutOfBoundsExceptionのコンストラクタを呼び出しています。parentキーワードは親クラスを指し、これによって生成したメッセージなどを親クラスに渡して、例外オブジェクトの基本的な情報を正しく設定しています。これは、クラスの継承において親クラスの機能を活用するための一般的な手法です。
子クラスでコンストラクタ __construct を独自に定義した場合、親クラスのコンストラクタは自動的には実行されません。そのため、parent::__construct() を明示的に呼び出し、親クラスの初期化処理を行うことが重要です。もしこの呼び出しを忘れると、例外メッセージやコードが正しく設定されず、getMessage() のようなメソッドが期待通りに動作しなくなります。サンプルコードのように、子クラスで受け取った引数(ユーザーID)を元に、親クラスが必要とする引数(メッセージ文字列)を組み立てて渡すのは、クラスを継承して機能を拡張する際の基本的な使い方です。