基礎

PHPのデストラクタ(__destruct)|オブジェクト破棄時の後処理

PHPのデストラクタは、オブジェクトが破棄されるときに自動的に呼び出される特殊なメソッドです。__destruct() という名前で定義し、ファイルのクローズ、データベース接続の切断、一時ファイルの削除など、後片付けの処理を行います。

コンストラクタ(__construct)がオブジェクトの「生成時」に呼ばれるのに対し、デストラクタは「破棄時」に呼ばれます。リソースの解放漏れを防ぐための仕組みです。

基本的な使い方

PHP
<?php
class MyClass {
    private string $name;

    public function __construct(string $name) {
        $this->name = $name;
        echo "{$this->name}: コンストラクタが呼ばれました\n";
    }

    public function __destruct() {
        echo "{$this->name}: デストラクタが呼ばれました\n";
    }
}

echo "--- オブジェクト生成 ---\n";
$obj = new MyClass("テスト");
echo "--- 処理中 ---\n";
echo "--- スクリプト終了 ---\n";
// スクリプト終了時にデストラクタが自動的に呼ばれる
実行結果
--- オブジェクト生成 ---
テスト: コンストラクタが呼ばれました
--- 処理中 ---
--- スクリプト終了 ---
テスト: デストラクタが呼ばれました

デストラクタは開発者が明示的に呼び出す必要はありません。変数のスコープ外になったとき、unset() で破棄したとき、またはスクリプトの終了時に自動的に呼ばれます。

明示的な破棄のタイミング

PHP
<?php
class Resource {
    public function __construct(private string $id) {
        echo "リソース{$this->id}を確保\n";
    }

    public function __destruct() {
        echo "リソース{$this->id}を解放\n";
    }
}

echo "--- 開始 ---\n";
$r1 = new Resource("A");
$r2 = new Resource("B");

echo "--- unsetでAを破棄 ---\n";
unset($r1);

echo "--- nullでBを破棄 ---\n";
$r2 = null;

echo "--- 終了 ---\n";
実行結果
--- 開始 ---
リソースAを確保
リソースBを確保
--- unsetでAを破棄 ---
リソースAを解放
--- nullでBを破棄 ---
リソースBを解放
--- 終了 ---

unset()null の代入でオブジェクトへの参照がなくなると、即座にデストラクタが呼ばれます。

実用的な例:一時ファイルの管理

PHP
<?php
class TempFile {
    private string $path;

    public function __construct(string $prefix = "tmp_") {
        $this->path = tempnam(sys_get_temp_dir(), $prefix);
        echo "一時ファイル作成: {$this->path}\n";
    }

    public function write(string $content): void {
        file_put_contents($this->path, $content);
    }

    public function read(): string {
        return file_get_contents($this->path);
    }

    public function __destruct() {
        if (file_exists($this->path)) {
            unlink($this->path);
            echo "一時ファイル削除: {$this->path}\n";
        }
    }
}

$temp = new TempFile("data_");
$temp->write("テストデータ");
echo "内容: " . $temp->read() . "\n";
unset($temp);  // デストラクタでファイルが自動削除される
echo "処理完了\n";
実行結果
一時ファイル作成: /tmp/data_abc123
内容: テストデータ
一時ファイル削除: /tmp/data_abc123
処理完了

ログ記録での活用

PHP
<?php
class Timer {
    private float $startTime;
    private string $label;

    public function __construct(string $label) {
        $this->label = $label;
        $this->startTime = microtime(true);
        echo "[{$this->label}] 計測開始\n";
    }

    public function __destruct() {
        $elapsed = round((microtime(true) - $this->startTime) * 1000, 2);
        echo "[{$this->label}] 計測終了: {$elapsed}ms\n";
    }
}

function heavyProcess(): void {
    $timer = new Timer("重い処理");
    // 擬似的に重い処理
    $sum = 0;
    for ($i = 0; $i < 1000000; $i++) {
        $sum += $i;
    }
    echo "計算結果: {$sum}\n";
    // 関数終了時にTimerのデストラクタが呼ばれる
}

heavyProcess();
実行結果
[重い処理] 計測開始
計算結果: 499999500000
[重い処理] 計測終了: 25.5ms
ポイント

デストラクタは引数を取ることができません。また、PHP 8.0以降ではデストラクタ内から例外をスローすると Fatal Error が発生するため、デストラクタ内ではtry-catchでエラーを処理するのが安全です。

注意

デストラクタの呼び出し順序はPHPのガベージコレクションに依存し、保証されません。複数のオブジェクトが相互参照している場合、デストラクタが呼ばれないこともあります。重要なリソース解放は明示的に行うメソッドも用意しておくと安全です。

まとめ

  • __destruct() はオブジェクト破棄時に自動的に呼ばれる
  • unset()null 代入、スクリプト終了時にデストラクタが実行される
  • 一時ファイルの削除、接続のクローズ、ログ記録などの後処理に最適
  • デストラクタは引数を取れず、例外をスローすべきでない
  • 呼び出し順序は保証されないため、重要な解放は明示的なメソッドも用意する