var_exportと__set_state()の使い方がよくわからない。
マニュアル読んでもわからない。
細かく調べてみた
var_exportはPHPソースを返すので便利
var_dumpと違い、var_exportはソースコードを返してくれる。
<?php #testA.php $a = array("a","b","c"); $str = var_export($a,true); echo $str;
これ実行するとソースコードが得られる。
>php testA.php array ( 0 => 'a', 1 => 'b', 2 => 'c', ) >
これは、便利だ。evalを組み合わせると配列をStringにして持ちまわせる。
Evalをするテスト
<?php #testB.php $a = array("a","b","c"); $str = var_export($a,true); eval('$_='.$str).";";# ';'をつけておく var_dump($_);
実行。
>php testB.php array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" } >
データベースの問い合わせ結果につかえる。データベースの問い合わせ結果が通常は連想配列なので、配列で渡さずともソースコードで持てる。多次元配列をデータベースに格納することにも応用できる。
オブジェクトのvar_exportは癖がある
じゃあクラスもSerializeせずに、var_exportでソースにしたいよね。
でもこれがなかなか苦労するんだ。
var_exportでオブジェクトをソースにすると、プロパティーだけが保存される
オブジェクトのVar_Export
<?php #testC.php class A { var $test1 ="1"; public $test2 ="2"; private $test3 ="3"; function T(){return;} }; $a = new A(); $str = var_export($a,true); echo $str;
実行結果
>php testC.php A::__set_state(array( 'test1' => '1', 'test2' => '2', 'test3' => '3', )) >
__set_stateってなんじゃ??
PHP5.1.0で追加されたMagicMethodだ。
マニュアルをよむとvar_export専用らしい
もとのオブジェクトに戻せるの??
たとえば、Classをこんな風にすると、もとにもどせる。
__set_stateはFactoryメソッドだと考えると理解が進む
__set_stateの利用例
<?php #testD.php class A { var $test1 ="1"; public $test2 ="2"; private $test3 ="3"; function T(){return;} public static function __set_state($props){ $a = new A(); foreach($props as $key=>$val){ //__setでなく可変変数でセットするのが楽 $a->$key = $val; } return $a; } }; $a = new A(); $str = var_export($a,true); eval('$_='.$str.";"); echo var_dump($_);
実行結果
>php testD.php object(A)#2 (3) { ["test1"]=> string(1) "1" ["test2"]=> string(1) "2" ["test3:private"]=> string(1) "3" } >
おおお、もどったよ!
__set_state()書くのがめんどくさくないか??
__set_stateを書かなければエラーで落ちる。どんなクラスでも上記の__set_stateをデフォルト実装していてほしいところ。__set_stateを自由にかけますよ!ってのがPHPの売り文句なんだろうか。
というわけで、var_exportを元に戻すfunctionを書いてみた
var_exportの逆を行うfunction
<?php #var_exportを元に戻す関数 function un_var_export($str){ $_buff = explode ( ":" , $str, 2 ); $class_name = $_buff[0]; $vars_str = explode("\n",$str); array_shift($vars_str); array_pop($vars_str); $func = create_function( null,' $arr = array('.implode($vars_str, "\n").'); $obj = new '.$class_name.'(); foreach( $arr as $key=>$val ){ $obj->$key = $val; } return $obj; ' ); $obj = $func(); return $obj; }
動作テスト
<?php #testE.php class A { var $test1 ="1"; public $test2 ="2"; private $test3 ="3"; function T(){return;} }; $a = new A(); $str = var_export($a,true).";" echo var_dump(un_var_export($str));
エラーになった
>php testE.php Fatal error: Cannot access private property A::$test3 in testE.php(72) : runtime-created function on line 7
privateな変数にはアクセスできないって。いいアイディアだと思ったが無理なようだ。
改良して再度挑戦してみる
マニュアルを読んでみるとphp_classkitというモジュールに出会う。
改良したun_var_export関数
<?php #var_exportを元に戻す関数 function un_var_export($str){ @dl ( "php_classkit" ); $_buff = explode ( ":" , $str, 2 ); $class_name = $_buff[0]; $obj = new $class_name(); $vars_str = explode("\n",$str); array_shift($vars_str); array_pop($vars_str); classkit_method_add( $class_name, "__set_state", '$props',' foreach($props as $key=>$val){ $this->$key = $val; }'); return $obj; }
動作テスト
<?php #testF.php class A { var $test1 ="1"; public $test2 ="2"; private $test3 ="3"; function T(){return;} }; $a = new A(); $str = var_export($a,true).";";# ';'をつけておく echo var_dump(un_var_export($str));
出来た!!
>php testF.php object(A)#2 (3) { ["test1"]=> string(1) "1" ["test2"]=> string(1) "2" ["test3:private"]=> string(1) "3" }
classkitモジュールって実はすごく便利なんじゃ・・・