PHPでFlex風のアクセサを作ってみる

個人的にはFlex(ActionScript3)のアクセサメソッドは、作る側にとっても使う側にとっても一番使い易いと思う。
こんな感じのアクセサをPHPでも使えたらきっと幸せになれるはず。
 
普通のpublicな変数だと見せかけて実はアクセサだった!っていう動き。
ここがとっても解りやすい。
 
アクセサ - うなの日記
http://d.hatena.ne.jp/unageanu/20070612/1181637634
 
2〜3個前の記事でやってるSSLの奴で、ライブラリ側はアクセサ作ってタイプヒンティングして、使う側はアクセサ経由で変数にアクセスして…という定番のパターンを律儀にやってて、流石に無理があると感じてきた。
何段構造か解らない程複雑な奥深いオブジェクトを扱いたい場合とかは、使う側はpublicな変数と直接やり取りしたい。
でもPHPだと型も糞もないから流石にpublic変数を晒してるのは流石にまずい。
と思ったのがきっかけ。
 

__get()と__set()でアクセサ

PHPでは、__get()とか__set()とかで存在しない変数に対してアクセスが来た時の動きを決められるらしい。
きっとその中でswitchとかしろって事なんだろうけど、使いづらい。
で、こんなの作った。
これなら使う側は普通のpublicな変数っぽく使えて、ライブラリ側はタイプヒンティング出来るから安心。
シンプルだけどなかなか便利なんじゃないかと。
デザインパターンでいう所の、Template Method的な。
なんでタイプヒンティングはPHP5からのものなのに例外をthrowしてくれないんだろう、気持ち悪い。

<?php
abstract class FlexAccessor
{
	public function __get($name)
	{
		$name = '__get_'.$name;
		return method_exists($this, $name) ? $this->$name() : null;
	}

	public function __set($name, $value)
	{
		$name = '__set_'.$name;
		method_exists($this, $name) ? $this->$name($value) : null;
	}
}

class TestClass extends FlexAccessor
{
	private $_strvar;
	private $_arrvar;


	// $o->strvar

	public function __get_strvar()
	{
		return $this->_strvar;
	}

	public function __set_strvar($value)
	{
		$this->_strvar = $value;
	}


	// $o->arrvar

	public function __get_arrvar()
	{
		return $this->_arrvar;
	}

	public function __set_arrvar(array $value)
	{
		$this->_arrvar = $value;
	}
}


$o = new TestClass();
$o->strvar = 'sss';
$o->arrvar = array('aaa', 'rrr', 'yyy');

echo $o->strvar."\n";
print_r($o->arrvar);
var_dump($o);

 

ボツ案

これはいかん。
いろいろといかん。

<?php
class Accessor
{
	private $_aaa = 'AAA';

	public function __get($name)
	{
		$name = '_'.$name;
		return isset($this->$name) ? $this->$name : null;
	}

	public function __set($name, $value)
	{
		$name = '_'.$name;
		if (Accessor::property_exists($this, $name)) {
			$this->$name = $value;;
		}
	}

	public static function property_exists($class, $property)
	{
		if (function_exists('property_exists')) {
			return property_exists($class, $property);
		}
		if (is_object($class)) {
			$class = get_class($class);
		}
		return array_key_exists($property, $class);
	}
}

class TestClass extends Accessor
{
	protected $_bbb = 'BBB';
}


$o = new TestClass();
var_dump($o->aaa);
var_dump($o->bbb);
var_dump($o->ccc);

 

先人

自力バリデートでアクセサを実装してる方がいた。
アクセス制限とタイプヒンティングをひたすらやりたい場合はこっちの方が使いやすそう。
 
PHPのアクセサ - CODE NAME: TUNE34
http://d.hatena.ne.jp/tune34/20080601/1212262870