■インスタンスメソッド
インスタンスメソッドは通常の関数と同じく以下のように宣言できる。また、インスタンスメソッドを呼び出すには、「インスタンス名->メソッド名」というように演算子->を用いる。
class Dog { public function bark(){ print('bow!'); } } $pochi = new Dog(); $pochi->bark();//bow!
$this
一方で、クラス内からメンバ関数を呼び出すには、以下のように$thisを用いる(静的メソッドの場合はキーワードselfを用いる)。
class Dog { public function bark(){ print('bow!'); } public function appeal($thing){ $this->bark(); print("Give me {$thing}!"); } } $pochi = new Dog(); $pochi->appeal('feeds');//bow!Give me feeds!
コンストラクタ
特別なクラスメソッドの一種でクラスがnew演算子でインスタンス化されるときに呼び出される関数である。
PHP5
class PersonClass { function __construct($name){ print($name); } } $john = new PersonClass('John');
PHP5 & PHP4ハイブリッド
PHP4ではクラス名と同じメソッド名がコンストラクタとして扱われていた。しかしこの方法には大きな欠点があり、クラス名を変える場合にコンストラクタ名まで変更しなくてはならなかった。そこでPHP5では、関数__constructがコンストラクタとして扱われるようになった。但し、関数__constructが存在しない場合は、インタプリタはPHP4形式のコンストラクタを探すようになっている。
class PersonClass { function __construct($name){ print($name); } function PersonClass($name){ print($name); } } $john = new PersonClass('John');
予備知識
PHPではコンストラクタの連鎖呼び出しは行われない。サブクラスのインスタンス作成時には、サブクラスのコンストラクタしか実行されない。
class Animal { protected $name; public function __construct($name){ $this->name = $name; } public function introduce(){ print("I'm {$this->name}! Nice to meet you!"); } } class Dog extends Animal{ public function __construct($name){ //no code } public function introduce(){ parent::introduce(); print(' bow!'); } public function bark(){ print("{$this->name}, bow!"); } } $pochi = new Dog('Pochi'); $pochi->introduce();//I'm ! Nice to meet you! bow! $pochi->bark();//, bow!
但し、以下のようにサブクラスでコンストラクタを宣言しない場合は、当然だがコンストラクタも継承されている。
class Animal { protected $name; public function __construct($name){ $this->name = $name; } public function introduce(){ print("I'm {$this->name}! Nice to meet you!"); } } class Dog extends Animal{ public function introduce(){ parent::introduce(); print(' bow!'); } public function bark(){ print("{$this->name}, bow!"); } } $pochi = new Dog('Pochi'); $pochi->introduce();//I'm Pochi! Nice to meet you! bow! $pochi->bark();//Pochi, bow!
コンストラクタに何らかの処理を加えたい場合、以下のようにサブクラスでコンストラクタを宣言(上書き)し、スーパークラスのコンストラクタを呼び出した後に追記する。
class Animal { protected $name; public function __construct($name){ $this->name = $name; } public function introduce(){ print("I'm {$this->name}! Nice to meet you!"); } } class Dog extends Animal { public function __construct($name){ parent::__construct($name); print("Hello, My name is {$this->name}!"); } public function introduce(){ parent::introduce(); print(' bow!'); } public function bark(){ print("{$this->name}, bow!"); } } $pochi = new Dog('Pochi');//Hello, My name is Pochi! $pochi->introduce();//I'm Pochi! Nice to meet you! bow! $pochi->bark();//Pochi, bow!
デストラクタ
PHP5では、オブジェクトの最後の参照が破棄されると、関数__destructが呼び出される。__destructには引数を設定できない。
class PersonClass { function __construct($name){ print(__METHOD__); } function __destruct(){ print(__METHOD__); } } $john = new PersonClass('John'); $terminator = $john; print('Copied!'); unset($john); print('T1000 killed John'); //PersonClass::__construct //Copied! //T1000 killed John //PersonClass::__destruct
$johnがunsetされた段階では、$terminatorの参照が残っているためにデストラクタは呼び出されない。リソースの開放などには非常に有用である。
■マジックメソッド
例えば、以下のように存在しないプロパティにアクセスしようとしても、何のエラーも出ない。また、雛型には存在しないようなプロパティが作られてしまう。
class Dog { public function bark(){ print('Bow!'); } } $pochi = new Dog(); $pochi->name = 'Pochi'; print($pochi->name);//Pochi
そのようなときに有用なのが__setメソッドと__getメソッドだ。以下のようにするとメッセージを表示するようにできる。また、コードを修正しエラーを発生させることもできる。
class Dog { public function bark(){ print('Bow!'); } public function __set($prop, $val){ print('Error:set'); } public function __get($prop){ print('Error:get'); } } $pochi = new Dog(); $pochi->name = 'Pochi';//Error:set print($pochi->name);//Error:get
各メソッドについて
- mixed __get(mixed $name)
- 存在しないプロパティの値を参照しようとしたときに呼び出される。但し、引数は必ず1つ記述しなければならない。
- void __set(string $name, mixed $value)
- 存在しないプロパティに値を代入しようとしたときに呼び出される。但し、引数は必ず2つ記述しなければならない。
- mixed __call(string $name, array $arguments)
- 存在しなかったメソッドが呼び出されたときに呼び出される。但し、デフォルトではFatal Errorが発生するので、実装しなくても安全である。
- void __clone(void)
- clone演算子が使用されたときの挙動を定義できる。
- void __sleep(void)
- serialize関数が呼び出されたときに、シリアル化の前に呼び出される。
- void __wakeup(void)
- unserialize関数が呼び出されたときに呼び出される。
- bool __isset(string $name)
- 未定義のプロパティに対してissetが使用されたときに実行される。
- void __unset(string $name)
- 未定義のプロパティにunsetが使用されたときに実行される。
- mixed __toString(void)
- クラスがprint関数などで文字列に変換される際の挙動を定義できる。
- mixed __set_state(array $propaty_pairs)
- var_export関数によって エクスポートされたクラスのためにコールされる。
■プロパティ
プロパティの宣言は必須ではないが、コードの保守性、可読性の向上のために明示することを強く勧める。
class Dog { private $name; public function __construct($name){ $this->name = $name; } public function bark(){ print($this->name . ', bow!'); } public function appeal($thing){ $this->bark(); print($this->name . ", Give me {$thing}!"); } } $pochi = new Dog('Pochi'); $pochi->bark();//Pochi, bow! $pochi->appeal('feeds');//Pochi, bow!Pochi, Give me feeds!
以下のようにプロパティを宣言しなくても、特にエラーではないがメンテナンスがしづらい。
class Dog { public function __construct($name){ $this->name = $name; } public function bark(){ print($this->name . ', bow!'); } public function appeal($thing){ $this->bark(); print($this->name . ", Give me {$thing}!"); } } $pochi = new Dog('Pochi'); $pochi->bark();//Pochi, bow! $pochi->appeal('feeds');//Pochi, bow!Pochi, Give me feeds! print($pochi->name);//Pochi
但し、最終ラインを見ても分かるように、プロパティは自動的にpublicとなってしまう。
プロパティのデフォルト値
以下のようにしてプロパティにデフォルト値を設定することができる。但し、デフォルト値として設定ができるのは、評価を必要としない単純な定数値や配列だけである。
class MyClass { private $str = 'sample'; private $num = 123456789; private $ary = array(1, 2, 3); public function getStr(){ return $this->str; } } $obj = new MyClass(); print($obj->getStr());//sample
また、一般的にはプロパティのアクセスコントロールはprivateやprotectedにしておく。外からアクセスする必要がある場合のみ、上述のgetStr関数のような「アクセサメソッド」を準備してアクセスできるようにする(情報の隠蔽性による判断)。