コンストラクタとデストラクタ
コンストラクタ
__construct
( mixed ...$values
= ""
) : void
PHP では、開発者がクラスのコンストラクタメソッドを宣言することが できます。コンストラクタメソッドを有するクラスは、新たにオブジェクトが 生成される度にこのメソッドをコールします。これにより、 そのオブジェクトを使用する前に必要な初期化を行うことができます。
注意:
子クラスがコンストラクタを有している場合、親クラスのコンストラクタが 暗黙の内にコールされることはありません。 親クラスのコンストラクタを実行するには、子クラスのコンストラクタの 中で parent::__construct() をコールすることが 必要です。 子クラスでコンストラクタを定義していない場合は、親クラスのコンストラクタを継承します (ただし、private 宣言されている場合は除く)。 これは、通常のクラスメソッドと同様です。
例1 継承とコンストラクタ
<?phpclass BaseClass { function __construct() { print "In BaseClass constructor\n"; }}class SubClass extends BaseClass { function __construct() { parent::__construct(); print "In SubClass constructor\n"; }}class OtherSubClass extends BaseClass { // BaseClass のコンストラクタを継承します}// In BaseClass constructor$obj = new BaseClass();// In BaseClass constructor// In SubClass constructor$obj = new SubClass();// In BaseClass constructor$obj = new OtherSubClass();?>
他のメソッドと異なり、親の __construct()
と異なるパラメータで __construct()
をオーバーライドしても PHP は
E_STRICT
エラーメッセージを出しません。
コンストラクタは、対応するオブジェクトを初期化する間に呼び出されるメソッドです。 よって、任意の数の引数を取ることが出来ます。 この引数は必須にすることもできますし、型宣言もできますし、デフォルト値を取ったりすることもできます。 コンストラクタの引数は、クラス名の後の括弧に、引数を置くことで指定することが出来ます。
例2 コンストラクタを引数と一緒に使う
<?phpclass Point { protected int $x; protected int $y; public function __construct(int $x, int $y = 0) { $this->x = $x; $this->y = $y; }}// 引数を両方渡す$p1 = new Point(4, 5);// 必須の引数のみを渡す。$y はデフォルト値0になります。$p2 = new Point(4);// 名前付き引数(PHP 8.0 以降):$p3 = new Point(y: 5, x: 4);?>
クラスにコンストラクタが存在しない場合、あるいは、コンストラクタに必須の引数がない場合、 括弧は省略できます。
古いスタイルのコンストラクタ
PHP 8.0.0 より前のバージョンでは、グローバル名前空間にあるクラスは、
クラス名と同じ名前のメソッドが古いスタイルのコンストラクタとして解釈されます。
この文法は推奨されておらず、E_DEPRECATED
が発生するものの、
まだこの関数をコンストラクタとして呼び出すことが出来ます。
__construct()
とクラス名と同じ名前のメソッドが両方定義されていた場合は、
__construct() がコンストラクタとして呼び出されます。
名前空間の中に存在するクラスについては、 PHP 8.0.0 以降では、 クラス名と同じ名前のメソッドはなんの意味も持ちません。
新しいコードでは、常に __construct() を使うようにしましょう。
コンストラクタのプロモーション
PHP 8.0.0 以降では、コンストラクタの引数を 対応するオブジェクトのプロパティに昇格させることができます。 コンストラクタの引数をプロパティに代入し、それ以外の操作を行わないことはよくあることです。 コンストラクタのプロモーションは、こういった場合の短縮記法を提供します。 上の例は、次のように書き直すことが出来ます。
例3 コンストラクタのプロモーションを使う
<?phpclass Point { public function __construct(protected int $x, protected int $y = 0) { }}
コンストラクタの引数に、可視性の修飾子が含まれている場合、 PHP はそれをオブジェクトのプロパティ、かつコンストラクタの引数であると解釈します。 そして、その引数の値をプロパティに代入します。 コンストラクタの本体は空にすることもできますし、 他の文を含めることも出来ます。 引数の値が対応するプロパティに代入された後、 追加の文が実行されます。
全ての引数をプロパティに昇格させる必要はありません。 昇格させる引数と、させない引数を混ぜることもできます。 プロパティに昇格した引数は、コンストラクタの呼び出しコードになんの影響も与えません。
注意:
PHP のエンジンが曖昧になってしまうため、 オブジェクトのプロパティは、callable 型にすることは出来ません。 そのため、昇格させる引数も callable 型にはできません。 しかし、それ以外の 型宣言 は許されています。
注意:
昇格したコンストラクタの引数に指定されたアトリビュートは、 プロパティと引数の両方にコピーされます。
静的な生成メソッド
PHP は、クラスひとつにつき、コンストラクタをひとつだけサポートしています。 しかし、場合によっては異なる入力を使い、 異なるやり方でオブジェクトを生成させるのが望ましい場合もあります。 その場合におすすめなのが、静的メソッドをコンストラクタのラッパーとして使うことです。
例4 静的な生成メソッドを使う
<?phpclass Product { private ?int $id; private ?string $name; private function __construct(?int $id = null, ?string $name = null) { $this->id = $id; $this->name = $name; } public static function fromBasicData(int $id, string $name): static { $new = new static($id, $name); return $new; } public static function fromJson(string $json): static { $data = json_decode($json); return new static($data['id'], $data['name']); } public static function fromXml(string $xml): static { // Put your own logic here. $data = convert_xml_to_array($xml); $new = new static(); $new->id = $data['id']; $new->name = $data['name']; return $new; }}$p1 = Product::fromBasicData(5, 'Widget');$p2 = Product::fromJson($some_json_string);$p3 = Product::fromXml($some_xml_string);
コンストラクタは外部から呼ばれることを防ぐため、private または protected にしておきます。 この場合、静的メソッドだけがクラスをインスタンス化するのに使えます。 なぜなら、静的メソッドは、同じオブジェクトのインスタンスでなくとも、 private なメソッドにアクセスできる同じクラスのメソッド定義として存在するからです。 コンストラクタを private にすることはオプションです。使い方によっては意味がないかもしれません...
上の public な静的メソッドは、オブジェクトをインスタンス化する3つの異なるやり方を示しています。
fromBasicData()
は、必要となる必須の引数を取り、 コンストラクタを呼ぶことでオブジェクトを生成し、その結果を返します。fromJson()
は、JSON文字列を受け取り、 コンストラクタで必要なフォーマットに変換するための前処理を行います。 その上で、新しいオブジェクトを返します。fromXml()
は、XML文字列を受け取り、前処理をします。 そして生のオブジェクトを生成します。コンストラクタは呼び出されていますが、 全ての引数はオプションなので、その実行はスキップされます。 結果を返す前に、オブジェクトのプロパティに直接値を代入しています。
上の3つの場合全てで、static
キーワードはコードが存在するクラスの名前として解釈されます。
この場合は Product
です。
デストラクタ
__destruct ( ) : void
PHP 5 では、C++ のような他のオブジェクト指向言語に似た概念のデストラクタが 導入されました。デストラクタメソッドは、 特定のオブジェクトを参照するリファレンスがひとつもなくなったときにコールされます。 あるいは、スクリプトの終了時にも順不同でコールされます。
例5 デストラクタの例
<?phpclass MyDestructableClass { function __construct() { print "In constructor\n"; } function __destruct() { print "Destroying " . __CLASS__ . "\n"; }}$obj = new MyDestructableClass();
コンストラクタと同様、親クラスのデストラクタがエンジンにより暗黙のうちに コールされるということはありません。親クラスのデストラクタを実行するには、 デストラクタの中で明示的に parent::__destruct() をコールする必要があります。 また、コンストラクタと同様、子クラスでデストラクタを定義していない場合は 親クラスのデストラクタを継承します。
exit() でスクリプトの実行を止めた場合にもデストラクタはコールされます。 デストラクタの内部で exit() をコールすると、 それ以降のシャットダウンルーチンを実行しません。
注意:
スクリプトのシャットダウン時にデストラクタがコールされた場合は、 HTTP ヘッダはすでに送信されています。スクリプトのシャットダウン時の作業ディレクトリは、 SAPI によっては (たとえば Apache など) 異なります。
注意:
デストラクタの中から (スクリプトの終了処理時に) 例外をスローしようとすると、致命的なエラーを引き起こします。