インスタンスが作成されるときに自動的に走るメソッドとして「コンストラクター」というメソッドが、多くの言語に存在します。PHPにも、この「コンストラクター」が存在します。
まずは実際にコードを書いて、コンストラクターの存在を確認してみます。
<?php class hoge { public function __construct() { echo "run constructor\n"; } } // $obj = new hoge();
__constructメソッドは、明示的には呼ばれていません。しかし「newされたタイミング」で自動で呼び出されます。その証左として、上述プログラムを動かすと「__constructメソッドをcallしていないのに、__constructメソッドが呼ばれている」様子が分かるかと思います。
また、コンストラクターと対になる概念として「デストラクター」というメソッドがあります。デストラクターは言語によってあったりなかったりしますが(典型的には、Javaが「デストラクターのない」言語です)、PHPではデストラクターが存在します。
デストラクターは「インスタンスが消去されるタイミング」で自動で呼び出されます。「消去されるタイミング」という状況を厳密に定義するのは少し難しいのですが、取りあえず「プログラム終了時」「変数のスコープが外れる」「インスタンスが入っている変数に別の値が代入される(典型的にはnullなどが代入される)」といったタイミングを意識しておくとよいでしょう。
上述した三つのパターンのサンプルプログラムをそれぞれ書いて、デストラクターの存在、およびデストラクターが走るタイミングを確認してみます。
<?php class hoge { public function __destruct() { echo "run destructor\n"; } } // プログラム終了時にデストラクターが走る $obj = new hoge();
<?php class hoge { public function __destruct() { echo "run destructor\n"; } } // function f() { $obj = new hoge(); } // 変数のスコープが外れる f(); sleep(5); // 「プログラム終了時にデストラクターが走る」と区別するためのsleep
<?php class hoge { public function __destruct() { echo "run destructor\n"; } } // インスタンスが入っている変数に別の値が代入される $obj = new hoge(); $obj = null; sleep(5); // 「プログラム終了時にデストラクターが走る」と区別するためのsleep
コンストラクターは、よく「インスタンスの初期化」などに用いられます。引数などで外部からデータを渡すことも可能です。エラーをreturnで返すことはできないので、「コンストラクターの処理でエラーになった」場合は、例外を投げる必要があります。
デストラクターはあまり使われることがありませんが、主として「コンストラクターで確保したリソースの解放」などに用いられることが多いです。そういった意味合いでも「コンストラクターと対になる」ことが多いと言えます。
変数において「再代入の是非」というのが今でも議論されています。「再代入」というのは簡単に書くと「一度変数に何か値をいれた後で、別の値を上書きする」ことです。
<?php $i = 10; var_dump($i); $i = 20; // ここで変数$iに、値を再代入 var_dump($i);
こういった「再代入」は、関数型言語、と呼ばれる言語の世界観では「できない(あるいは好ましくない)」とされています。
この「再代入の禁止」というのは、手続き型言語の一つであるPHPを「普通に」学んでいると、「全面的に取り入れる」のは難しいと思いますが、クラスの設計によっては「一度入れられた値を変える必要がない(または変えるとバグが発生しやすくなる)」もの、ということがあり得ます。
そういったときに「コンストラクターで値を設定、その後に値を変えることができない」クラス、というパターンが有効な場合があり、それを「イミュータブルなオブジェクト(不変オブジェクト)」という言い方をします。
実装例を書いてみましょう。
<?php class hoge { public function __construct($v) { $this->_val = $v; } public function getVal() { return $this->_val; } // private $_val; } // $obj = new hoge('vall'); var_dump( $obj->getVal() );
イミュータブルなオブジェクトでは、コンストラクターでデータを決定させます。また、setterは作成しません。プロパティはもちろんprivateになります。
イミュータブルなインスタンスは「再代入がない」ので、結果的に「そのインスタンスがどんな情報を持っているか」が明示的であり、「プログラムの流れによってインスタンスの状態が遷移する可能性がない」と言えます。
また、その状況は結果的に「デバッグの容易性」「テストパターンの減少」など、いくつかのメリットを生じさせます。本連載のメインターゲットである「初級本を読み終わった/PHP 5技術者認定初級試験には合格した」くらいの人だと、まだ少し難しい概念ですが、今は「そんなものもあるんだ」といった程度に覚えておいてください。
こういったさまざまな概念を状況に合わせて使いこなせるようになると、プログラミングの腕前が上がって、より良いコードが書けるようになります。
次回は、オブジェクト指向プログラミングの中でも一つ大きなポイントになる「継承」について、書き方と考え方の両方向から解説していきます。
Copyright © ITmedia, Inc. All Rights Reserved.