[PHP] コンストラクタとデストラクタ

コンストラクタ

PHPでクラスを利用する際に、最初にnew演算子によってクラスのインスタンスを作成するという作業を行いますが、この時に実行されるメソッドをコンストラクタと言います。

コンストラクタは省略可能で、省略した場合引数を持たないデフォルトのコンストラクタが内部的に用意されます。

コンストラクタの定義構文

public function __construct(引数) {
    // プロパティなどの初期化処理
}

[実装例]コンストラクタでメンバー変数を初期化する

コード

class Test{
    private int $id;
    private string $name;

    public function __construct(int $id, string $name) {
        echo __METHOD__, "\n";
        $this->id = $id;
        $this->name = $name;
    }
}

$test = new Test(1, "Test Name");
var_dump($test);

実行結果

$ php test_construct.php
Test::__construct
object(Test)#1 (2) {
  ["id":"Test":private]=>
  int(1)
  ["name":"Test":private]=>
  string(9) "Test Name"
}

[間違った実装例]引数なしのコンストラクタを呼び出す

引数ありのコンストラクタを定義した状態で、引数なしのコンストラクタを呼び出すとエラーになります。コンストラクタをクラスに明示的に定義した時点で、デフォルトのコンストラクタは無効になります。

コード

class Test{
    private int $id;
    private string $name;

    public function __construct(int $id, string $name) {
        echo __METHOD__, "\n";
        $this->id = $id;
        $this->name = $name;
    }
}

$test = new Test();
var_dump($test);

実行結果

$ php test_construct.php

Fatal error: Uncaught ArgumentCountError: Too few arguments to function
    Test::__construct(), 0 passed in .\test_construct.php on line 19 and
    exactly 2 expected in .\test_construct.php:12

Stack trace:
#0 .\test_construct.php(19): Test->__construct()
#1 {main}
  thrown in .\test_construct.php on line 12

解決方法

PHPにJavaのオーバーロードのようなものは無いので、複数のコンストラクタを定義することはできませんが、引数の初期値を設定することでこのエラーは回避可能です。

public function __construct(int $id = 0, string $name = "") {
    echo __METHOD__, "\n";
    $this->id = $id;
    $this->name = $name;
}

(なお、これは一つの方法であり、やり方はいくつかあると思います。)

[実装例]親クラスのコンストラクタを呼び出す

生成されるインスタンスがサブクラスの場合、親クラスのインスタンスは明示的に呼び出さなければ実行されません。

必須ではありませんが、親クラスからインスタンスを生成する必要がある場合は、parentキーワードを使用して、親クラスのコンストラクタを呼び出します。

コード

class SuperClass {
    public function __construct() {
        echo __METHOD__, "\n";
    }
}

class Test extends SuperClass {
    private int $id;
    private string $name;

    public function __construct(int $id, string $name) {
        parent::__construct();

        echo __METHOD__, "\n";
        $this->id = $id;
        $this->name = $name;
    }
}

$test = new Test(1, "Test Name");
var_dump($test);

なお、親クラスのコンストラクタの呼び出し(parent::__construct)はどこに書いてもエラーにはならないので、呼び出しのタイミングによって不整合が起きないように注意する必要があります。一般的にはサブクラスのコンストラクタの先頭で呼び出します。

実行結果

$ php test_construct.php
SuperClass::__construct
Test::__construct
object(Test)#1 (2) {
  ["id":"Test":private]=>
  int(1)
  ["name":"Test":private]=>
  string(9) "Test Name"
}

デストラクタ

デストラクタはインスタンス化したクラスのオブジェクトが破棄されるタイミングで呼び出されるメソッドです。クラス内で使用したリソースの開放など、主に終了するときの処理を記述します。

なお、親クラスのデストラクタは、コンストラクタと一緒で明示的に呼び出さない限り実行されることはありません。

デストラクタの定義構文

public function __destruct() {
    // 使用したリソースの開放などの処理
}

デストラクタが呼ばれるタイミングについて

デストラクタが呼ばれる正確なタイミングは、インスタンス化されたオブジェクト変数がどこからも参照されなくなった時です。これを明示的に呼び出す方法は、オブジェクト変数にnullを代入する、またはunset関数で破棄する、などの方法があります。

コード

以下のコードでは、Testクラスのオブジェクト生成後、オブジェクト変数にnullを代入してデストラクタを呼び出しています。

class Test {
    public function __construct() {
        echo __METHOD__, "\n";
    }

    public function __destruct() {
        echo __METHOD__, "\n";
    }
}

$test = new Test();

$test = null;

sleep(2);

実行結果

実行結果を確認すると、オブジェクト変数にnullを代入した段階でデストラクタが呼び出され、2秒スリープしてプログラムが終了していることが分かります。

$ php test_construct.php
Test::__construct
Test::__destruct

(2秒スリープしてプログラムが終了)

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)