3 つのクラスを定義し、各々に別々のストレージメソッドを実装します。
例1 storage_classes.inc
<?php
class FileStorage {
var $data;
function FileStorage($data)
{
$this->data = $data;
}
function write($name)
{
$fp = fopen(name, "w");
fwrite($fp, $this->data);
fclose($data);
}
}
class WDDXStorage {
var $data;
var $version = "1.0";
var $_id; // "private" 変数
function WDDXStorage($data)
{
$this->data = $data;
$this->_id = $this->_genID();
}
function store()
{
if ($this->_id) {
$pid = wddx_packet_start($this->_id);
wddx_add_vars($pid, "this->data");
$packet = wddx_packet_end($pid);
} else {
$packet = wddx_serialize_value($this->data);
}
$dbh = dba_open("varstore", "w", "gdbm");
dba_insert(md5(uniqid("", true)), $packet, $dbh);
dba_close($dbh);
}
// プライベートメソッド
function _genID()
{
return md5(uniqid(rand(), true));
}
}
class DBStorage {
var $data;
var $dbtype = "mysql";
function DBStorage($data)
{
$this->data = $data;
}
function save()
{
$dbh = mysql_connect();
mysql_select_db("storage", $dbh);
$serdata = serialize($this->data);
mysql_query("insert into vars ('$serdata',now())", $dbh);
mysql_close($dbh);
}
}
?>
この定義済みクラスを用いていくつかのオブジェクトをインスタンス化し、 集約や集約の解除を行いつつ随時オブジェクトの情報を出力します。
例2 test_aggregation.php
<?php
include "storageclasses.inc";
// ユーティリティ関数
function p_arr($arr)
{
foreach ($arr as $k => $v)
$out[] = "\t$k => $v";
return implode("\n", $out);
}
function object_info($obj)
{
$out[] = "クラス: " . get_class($obj);
foreach (get_object_vars($obj) as $var=>$val) {
if (is_array($val)) {
$out[] = "プロパティ: $var (array)\n" . p_arr($val);
} else {
$out[] = "プロパティ: $var = $val";
}
}
foreach (get_class_methods($obj) as $method) {
$out[] = "メソッド: $method";
}
return implode("\n", $out);
}
$data = array(M_PI, "kludge != cruft");
// 基本オブジェクトを作成する
$fs = new FileStorage($data);
$ws = new WDDXStorage($data);
// オブジェクトの情報を表示する
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
echo "\n\$ws オブジェクト\n";
echo object_info($ws) . "\n";
// 集約を行う
echo "\n\$fs を WDDXStorage クラスに集約します\n";
aggregate($fs, "WDDXStorage");
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
echo "\nそれを DBStorage クラスに集約します\n";
aggregate($fs, "DBStorage");
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
echo "\nWDDXStorage を集約から解除します\n";
deaggregate($fs, "WDDXStorage");
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
?>
出力内容を見ながら、PHP の集約についての副作用や制限事項を 考えてみましょう。 まず、新しく作成されたオブジェクト $fs および $ws は、期待通りの (対応するクラス定義に もとづく) 結果を出力します。 PHP では実際のところクラス/オブジェクトの要素についてパブリック/ プライベートの区別はありませんが、集約の際には クラス/オブジェクトのプライベート要素はアンダースコア文字 ("_") で始まるとみなします。
$fs オブジェクト クラス: filestorage プロパティ: data (array) 0 => 3.1415926535898 1 => kludge != cruft メソッド: filestorage メソッド: write $ws オブジェクト クラス: wddxstorage プロパティ: data (array) 0 => 3.1415926535898 1 => kludge != cruft プロパティ: version = 1.0 プロパティ: _id = ID::9bb2b640764d4370eb04808af8b076a5 メソッド: wddxstorage メソッド: store メソッド: _genid
次に $fs を WDDXStorage クラスと集約し、オブジェクトの情報を出力します。 $fs は今でも FileStorage のままですが、プロパティ $version およびメソッド store() が存在することがわかるでしょう。これらは いずれも WDDXStorage で定義されているものです。 注意すべき点は、クラスで定義されているプライベート要素は集約されていない ということです。それらは $ws オブジェクトの中には 存在します。また、WDDXStorage のコンストラクタも 存在しません。これを集約するのは論理的ではありません。
$fs を WDDXStorage クラスに集約します $fs オブジェクト クラス: filestorage プロパティ: data (array) 0 => 3.1415926535898 1 => kludge != cruft プロパティ: version = 1.0 メソッド: filestorage メソッド: write メソッド: store
集約処理は、積み重ねていくことが可能です。そこで今度は $fs と DBStorage を 集約します。これにより、定義されているすべてのクラスの 保存処理メソッドを使用可能なオブジェクトができあがります。
それを DBStorage クラスに集約します $fs オブジェクト クラス: filestorage プロパティ: data (array) 0 => 3.1415926535898 1 => kludge != cruft プロパティ: version = 1.0 プロパティ: dbtype = mysql メソッド: filestorage メソッド: write メソッド: store メソッド: save
最後に、プロパティやメソッドを動的に集約したのと同じ方法で、 集約したプロパティやメソッドを解除することも可能です。 $fs から WDDXStorage クラスの集約を解除すると、このような結果になります。
WDDXStorage を集約から解除します $fs オブジェクト クラス: filestorage プロパティ: data (array) 0 => 3.1415926535898 1 => kludge != cruft プロパティ: dbtype = mysql メソッド: filestorage メソッド: write メソッド: save
上で説明しきれなかったことがひとつあります。それは、集約処理の際には 既存のプロパティやメソッドは上書きされないということです。例えば、 FileStorage クラスでは $data というプロパティを定義しており、 WDDXStorage クラスでも同名のプロパティが 定義されていますが、このプロパティが FileStorage のインスタンス化の際に 取得したプロパティの内容を上書きすることはありません。