コンストラクターを作成するとき、「__construct」というメソッドを定義しました。このアンダースコア2つから始まるメソッドは、PHPのクラス定義にあらかじめ決められている「マジックメソッド」と呼ばれるメソッドの一つです。次の種類があり、それぞれ決められたタイミングで呼び出されます。
__construct | コンストラクター。生成される時に実行される |
__destruct | デストラクター。利用を終了するときに実行される |
__call | private, protectedなどで宣言されたメソッドが呼び出されたとき |
__callStatic | 同上の静的メソッドが呼び出されたとき |
__get | 同上のプロパティを呼び出されたとき |
__set | 同上のプロパティに値を代入しようとしたとき |
__isset | isset, emptyのパラメーターとして同上のプロパティを指定したとき |
__unset | unsetのパラメーターとして同上のプロパティが呼び出されたとき |
__debugInfo | var_dumpのパラメーターに指定されたとき |
__sleep | serialize()が実行されるとき |
__wakeup | unserialize()が実行されるとき |
__invoke | インスタンスをファンクションとして呼び出したとき |
__set_state | var_export() によって エクスポートされるとき |
__clone | インスタンスがクローンされるとき |
インスタンスを直接出力できる __toString
例えば、「__toString」を利用すると、インスタンスを直接出力できるようになります。例えば、次のようなクラスを準備しましょう。
class Item {
public string $name;
public string $price;
// インスタンスの内容を出力する
public function __toString() {
return $this->name, ' / ', number_format($this->price), '円';
}
}
これで次のようにインスタンスを作成しましょう。
$item = new Item();
$item->name = 'PHP入門';
$item->price = 2300;
そして、この「$item」を直接画面に出力してみます。
echo $item;
すると、自動的に「__toString」メソッドが呼び出されて、次のように画面に表示されます。
PHP入門 / 1,500円
プロパティを決められたフォーマットで出力することが多い場合などに、便利に利用できます。
プロパティの代わりにゲッター・セッターを準備する – __get, __set
プロパティに直接アクセスしてしまうと、不正な値を代入してしまうことがあるため、ゲッターやセッターを準備するのが一般的です。しかし、「setXXX」や「getXXX」といった独自のメソッドをプロパティの数だけ準備する代わりに、マジックメソッドを利用するとスマートに実装することができます。次の例を見てみましょう。
class Item {
private string $name;
}
ここでは、商品名を管理する「$item」というプロパティを定義しましたが、privateで宣言しているためこのままでは次のように呼び出すことはできません。
$item = new Item();
$item->name = 'PHP入門';
ここで、次のようにマジックメソッドを定義します。
class Item {
private $props = [];
// セッター
public function __set($name, $value) {
$this->props[$name] = $value;
}
// ゲッター
public function __get($name) {
return $this->props[$name];
}
}
こうすると、次のように「$name」というプロパティ(のようなもの)に値を入れることができます。
$item = new Item();
$item->name = 'PHP入門';
この時、正確には「$name」というプロパティがあるわけではなく、「$props」という配列のプロパティがあり、そこの各プロパティの要素を格納するというしくみになっています。これを利用するメリットは、セッター・ゲッターとして検査などを入れやすい点があります。
検査のロジックを入れる
次のように検査ロジックを入れやすいことがあります。
// セッター
public function __set($name, $value) {
if ($name === 'name' && $value === '') {
// 名前が空の場合は「名前未設定」と代入する
$this->props[$name] = '名称未設定';
} else {
$this->props[$name] = $value;
}
}
うまく利用すると便利ですが、どんなプロパティがあるかなどが分かりにくくなってしまうため、多用はしない方がよいでしょう。