クラスのマジックメソッド __set, __get は、存在しないクラスプロパティや private, protected 等で保護されたプロパティにアクセスする際に自動的に呼び出されます。(ゲッターメソッド/セッターメソッド)
これを使うことでプロパティを取得する際に値を加工して返したり、セットする値が正しいかどうかを確かめたりすることができます。また、private プロパティに読み取りのための __get 処理を用意すると読み取り専用のような振る舞いをさせることができます。
下記のサンプルはクラスに幅(width)と高さ(height)を渡し、面積(area)を返すものと、読み取り専用のプロパティの値を変更しようと試みるテストです。
<?php class Sample { private $width; private $height; private $readonly = 'test'; function __get($name){ if($name === 'area'){ return $this->width * $this->height; } else if($name === 'readonly'){ return $this->readonly; } } function __set($name, $value){ if($name === 'readonly'){ throw new Exception('Attempted to assign to readonly property'); } else if( $name === 'width' || $name === 'height' ){ if(!is_numeric($value)){ throw new Exception('Invalid value'); } $this->{$name} = $value; } } }
・面積の計算
$sample = new Sample(); $sample->width = 30; $sample->height = 20; echo $sample->area;
結果: 600
インスタンス $sample に幅と高さの値をセットしています。
width と height は private であるため、通常は値の読み書きはできませんが、__set() を用意しているのでそちらを通して値をセットできます。
面積を示すプロパティ area は宣言されていませんが、__get() の中で処理を用意することで存在するプロパティであるかのように動作します。これは getArea() のような専用の関数を用意するのと同じ役割です。
幅と高さを指定する際、数字以外の値が渡されることの無いよう is_numeric() で簡易チェックをしています。これにより「abc」のような文字列をセットしようとしても例外が発生します。
・読み取り専用プロパティへのアクセス
$sample = new Sample(); try { echo $sample->readonly; // 「test」 $sample->readonly = 'hello'; // 例外が発生 } catch(Exception $e){ echo $e->getMessage(); }
プロパティ readonly も private なのでそのままでは読み書きできません。
__get()、__set() を両方用意すれば読み書きが可能になりますが、__set() にセットを禁止する処理を加えているので書き込もうとすると例外が発生します。
Similar Posts:
- [PHP]コンストラクタ内で例外を投げるのは危険?
- [PHP]3次スプライン曲線を使ったスプライン補間
- [PHP]よくあるエラーメッセージの原因と対処法 2
- [PHP]似た画像を検索して近い順番に並べる(類似画像検索)
- [PHP]FTPでアップロードやダウンロード等のファイル操作を行う
- [PHP]似た色合いの画像をRGB値をもとに探す
- [PHP]HSV(HSB)色空間を比較して似た色合いの画像を検索する
- [PHP]クラスにメソッドを動的に追加する
21行目の
throw new Exception(‘Invalid value’);
は、debug_backtrace();で取得した呼び出し元のファイル名と行番号も設定してあげると親切かと思います。