コンストラクタとデストラクタ
デストラクタって・・・何???
「コンストラクタ」は“オブジェクトの生成時に自動的にコールされる特殊なメンバ関数”でした。これはPHP4にもありましたが、PHP5になって「デストラクタ」という愉快な仲間が新登場しました。で、「デストラクタ」は“オブジェクトが消滅する時に自動的にコールされる特殊なメンバ関数”です。
PHP5式コンストラクタ/デストラクタ
PHP4では、クラス名と同じ名前のメンバ関数を定義すると、それが「コンストラクタ」になりました。PHP5でも、互換性のためにPHP4と同様にして「コンストラクタ」をつくれますが、“PHP5式”では「__construct()
(アンダーライン2本で始まる)」が「コンストラクタ」となり、また「__destruct()
(アンダーライン2本で始まる)」が「デストラクタ」になります。
ちなみに、“PHP4式”のコンストラクタと“PHP5式”のコンストラクタの両方が定義されていた場合は、“PHP5式”のコンストラクタがコールされます。
なお、PHPでは「__
(アンダーライン2本)」で始まるクラスのメンバ関数名と通常の関数名を、“特殊な関数”として予約していて、「__
(アンダーライン2本)」で始まる関数名を付けないよう推奨されているので、付けない様にしましょう。
デストラクタの呼ばれ時
“「コンストラクタ」の呼ばれ時”はご存知の通り、“「new
演算子」でオブジェクトが生成された時”ですが、では“「デストラクタ」の呼ばれ時”の“オブジェクトが消滅する時”って具体的にどんな時なのか?それは“どの変数からも参照されなくなった時”です。以下のサンプルと結果をご覧下さい。
<pre>
<?php
class BASE{
protected function __construct(){
echo "[][] begin BASE constructor [][]\n";
echo "[][] end BASE constructor [][]\n";
}
protected function __destruct(){
echo "~~~~ begin BASE destructor ~~~~\n";
echo "~~~~ end BASE destructor ~~~~\n";
}
}
class SUB extends BASE{
public function __construct(){
echo "[][][] begin SUB constructor [][][]\n";
parent::__construct();
echo "[][][] end SUB constructor [][][]\n\n";
}
public function __destruct(){
echo "~~~~~~ begin SUB destructor ~~~~~~\n";
parent::__destruct();
echo "~~~~~~ end SUB destructor ~~~~~~\n\n";
}
}
class HODE{
private $id;
public function __construct($id){
$this->id = $id;
echo "[][][] HODE({$this->id}) constructor [][][]\n\n";
}
public function __destruct(){
echo "~~~~~~ HODE({$this->id}) destructor ~~~~~~\n\n";
}
}
#オブジェクトを生成(変数に代入しない)
echo '>new SUB;', "\n\n";
new SUB;
$i = 0;
#オブジェクトを生成(変数に代入する)
echo '>$hode = new HODE(0);', "\n\n";
$hode = new HODE($i++);
#オブジェクトを生成
echo '>$hode = new HODE(1);', "\n",
'>$hode2 = new HODE(2);', "\n",
'>$hode3 = new HODE(3);', "\n",
'>$hode4 = new HODE(4);', "\n\n";
$hode = new HODE($i++);
$hode2 = new HODE($i++);
$hode3 = new HODE($i++);
$hode4 = new HODE($i++);
#アンセットする
echo '>unset($hode3);', "\n\n";
unset($hode3);
#「die()」でスクリプト終了。
die("************ Called die() ************\n\n");
?>
</pre>
>new SUB;
[][][] begin SUB constructor [][][]
[][] begin BASE constructor [][]
[][] end BASE constructor [][]
[][][] end SUB constructor [][][]
~~~~~~ begin SUB destructor ~~~~~~
~~~~ begin BASE destructor ~~~~
~~~~ end BASE destructor ~~~~
~~~~~~ end SUB destructor ~~~~~~
>$hode = new HODE(0);
[][][] HODE(0) constructor [][][]
>$hode = new HODE(1);
>$hode2 = new HODE(2);
>$hode3 = new HODE(3);
>$hode4 = new HODE(4);
[][][] HODE(1) constructor [][][]
~~~~~~ HODE(0) destructor ~~~~~~
[][][] HODE(2) constructor [][][]
[][][] HODE(3) constructor [][][]
[][][] HODE(4) constructor [][][]
>unset($hode3);
~~~~~~ HODE(3) destructor ~~~~~~
************ Called die() ************
~~~~~~ HODE(2) destructor ~~~~~~
~~~~~~ HODE(1) destructor ~~~~~~
~~~~~~ HODE(4) destructor ~~~~~~
「コンストラクタ」と「デストラクタ」の呼ばれ時を追跡してみますと、下記のようになります。
- 「new SUB;
」でオブジェクト生成。
- 「コンストラクタ」がコールされる。
- その後変数に代入される事なく文が終了。
- オブジェクトが何処からも参照されなくなったので「デストラクタ」がコールされる。
- 「$hode = new HODE(0);」でオブジェクト生成。
- 「HODE(0)」の「コンストラクタ」がコールされる。
- 「$hode = new HODE(1);」、「$hode2 = new HODE(2);」、「$hode3 = new HODE(3);」、「$hode4 = new HODE(4);」でオブジェクト生成。
- 「HODE(1)」の「コンストラクタ」がコールされる。
- 「$hode」が更新され、「HODE(0)」の「デストラクタ」がコールされる。
- 「HODE(2)」、「HODE(3)」、「HODE4」の「コンストラクタ」がコールされる。
- 「unset($hode3);」でアンセット。
- 「HODE(3)」の「デストラクタ」がコールされる。
- 「
die()
」でスクリプトを終了させる。
- 各変数がアンセットされていき、「HODE(2)」、「HODE(1)」、「HODE4」の「デストラクタ」がコールされる。
- スクリプト終了。
クラスを継承した場合、派生クラスのオブジェクトを生成・削除しても、基底クラスの「コンストラクタ」と「デストラクタ」は自動的にコールされないので、「parent::__construct()」や「parent::__destruct()」のように手動?でコールします。
更にもう1サンプルご覧下さい。
<pre>
<?php
class HODE{
private $id;
public function __construct($id){
$this->id = $id;
echo "[][][] HODE({$this->id}) constructor [][][]\n\n";
}
public function __destruct(){
echo "~~~~~~ HODE({$this->id}) destructor ~~~~~~\n\n";
#未定義のメソッドをコールしてエラーを発生させる。
$this->hode();
}
}
$hode1 = new HODE(1);
$hode2 = new HODE(2);
$hode3 = new HODE(3);
#未定義の関数をコールしてエラーを発生させる。
hode();
?>
</pre>
[][][] HODE(1) constructor [][][]
[][][] HODE(2) constructor [][][]
[][][] HODE(3) constructor [][][]
Fatal error:その関数、未定義ですから。
~~~~~~ HODE(1) destructor ~~~~~~
Fatal error:そのメソッド、未定義ですから。
発生した時点でスクリプトが終了させられる「E_ERROR
」エラーが発生しましたが、ちゃんと「デストラクタ」はコールされました。“「デストラクタ」は何が何でもコールされる”ようです。
が、よく見ると、「デストラクタ」を持つオブジェクトが3つあり、本来ならオブジェクトの消滅時にこの3つ分の「デストラクタ」がコールされるはずなのに1つ分しかコールされていません。
未定義の関数をコールして「E_ERROR
」エラーを発生させ、「デストラクタ」がコールされましたが、さらにその「デストラクタ」内で未定義のメソッドをコールして「E_ERROR
」エラーを発生させたら、それ以降、別のオブジェクトの「デストラクタ」はコールされませんでした。
「die()
」による人為的なスクリプトの終了の場合も「E_ERROR
」エラー発生による強制終了の場合も、オブジェクトの消滅時には何が何でも「デストラクタ」はコールされますが、“「デストラクタ」内の処理によってスクリプトが終了する場合は、それ以降、別の「デストラクタ」はコールされません”。
作成日:2004年12月21日 最終更新日:2004年12月21日
【印刷モード風モード で表示】