・ インスタンスのクラスを変更
・ メソッドの動的な追加
幾つかのオブジェクトシステムではインスタンスのクラスを変えられますが、それを php で真似る。
■ まずは結果
// 変換先クラスサンプル
class foo{
public $p = 'yo!';
public function dump(){var_dump($this);}
}
// 変更させるインスタンス
$obj = new stdClass;
$obj->d = 'hi!';
// 変更前のvar_dump
var_dump($obj);// object(stdClass)#1 (1) { ["d"]=> string(3) "hi!" }
echo "<br><br>";
// クラスを変えてしまう
change_class(&$obj, 'foo');
// 変更後のvar_dump
$obj->dump();// object(foo)#2 (2) { ["p"]=> string(3) "yo!" ["d"]=> string(3) "hi!" }
echo "<br><br>";
// foo そのものから作ると
$foo = new foo;
var_dump($foo);// object(foo)#1 (1) { ["p"]=> string(3) "yo!" }
echo "<br><br>";
// 一見するとメソッドの動的な追加のような事も
add_method(&$obj, 'public function hello(){echo "hello!<br />";}');
$obj->hello();// hello!
// メソッド追加後の var_dump
$obj->dump();// object(add_method_0)#3 (2) { ["p"]=> string(3) "yo!" ["d"]=> string(3) "hi!" }
echo "<br><br>";
class foo{
public $p = 'yo!';
public function dump(){var_dump($this);}
}
// 変更させるインスタンス
$obj = new stdClass;
$obj->d = 'hi!';
// 変更前のvar_dump
var_dump($obj);// object(stdClass)#1 (1) { ["d"]=> string(3) "hi!" }
echo "<br><br>";
// クラスを変えてしまう
change_class(&$obj, 'foo');
// 変更後のvar_dump
$obj->dump();// object(foo)#2 (2) { ["p"]=> string(3) "yo!" ["d"]=> string(3) "hi!" }
echo "<br><br>";
// foo そのものから作ると
$foo = new foo;
var_dump($foo);// object(foo)#1 (1) { ["p"]=> string(3) "yo!" }
echo "<br><br>";
// 一見するとメソッドの動的な追加のような事も
add_method(&$obj, 'public function hello(){echo "hello!<br />";}');
$obj->hello();// hello!
// メソッド追加後の var_dump
$obj->dump();// object(add_method_0)#3 (2) { ["p"]=> string(3) "yo!" ["d"]=> string(3) "hi!" }
echo "<br><br>";
■ 自前の環境
PHP Version 5.2.3
System Windows NT
Server API Apache 2.0
クラスを変更する関数他
// インスタンスのクラスを変える
function change_class(&$obj, $new){
$old = get_class($obj);
$ser = serialize($obj);
$ser = preg_replace("/O:\d+:\"$old\"/", "O:" . strlen($new) . ":\"$new\"", $ser);
$obj = unserialize($ser);
}
// 一見クラスメソッドを動的に追加したような事もできる。
function add_method(&$obj, $mtd){
static $num = 0;
$old = get_class($obj);
$new = 'add_method_' . $num++;
$ext = "class $new extends $old { $mtd }";
eval($ext);
$ser = serialize($obj);
$ser = preg_replace("/O:\d+:\"$old\"/", "O:" . strlen($new) . ":\"$new\"", $ser);
$obj = unserialize($ser);
return $ext;
}
function change_class(&$obj, $new){
$old = get_class($obj);
$ser = serialize($obj);
$ser = preg_replace("/O:\d+:\"$old\"/", "O:" . strlen($new) . ":\"$new\"", $ser);
$obj = unserialize($ser);
}
// 一見クラスメソッドを動的に追加したような事もできる。
function add_method(&$obj, $mtd){
static $num = 0;
$old = get_class($obj);
$new = 'add_method_' . $num++;
$ext = "class $new extends $old { $mtd }";
eval($ext);
$ser = serialize($obj);
$ser = preg_replace("/O:\d+:\"$old\"/", "O:" . strlen($new) . ":\"$new\"", $ser);
$obj = unserialize($ser);
return $ext;
}
キッタネーと思った方。正解です。(コードの美醜じゃなくw)
結局のところ serialize / unserialize です。
そして「まねると危険」なコードです。
間違っても安易にセッションに入れたりはしないでください。
何にせよ、カチっとした php では、お行儀が良いようには見えない。
無理矢理ですしねぇ。
ただ、結局の所、セッションでの復元の際、クラスの定義内容を変える場合と同じ事になります。
include するファイルを変えるなどですね。
そう言った点で意識して使ってる人もあるかもしれません。
私はそんな流動的なアルゴリズムは怖くて(仕事では)書けませんがw
それと、javascript メインな人にも抵抗感が無いかも知れない。
仕様として実装されてる CLOS系のオブジェクトシステム の人にも出来て当然かも知れません。
ただこれ、クラスを渡り歩けるので面白いです。
※ serialize しているので serialize の機能による制約があります。
※ あーそうそう。preg_replace はいい加減なので(色々とかw)気を付けてください。
この記事へのコメント