PHPのnewに再チャレンジ PHP5.3
PHPのnewはこれで置き換えだ - なんたらノート 第二期 で書いたのは、どうもPHP5.3ではダメっぽいです。
PHP5.3では、evalの実行コンテキストが、関数内ではなくグローバルになる(でも変数はローカルのをレキシカルに束縛してる)というトリビアがありました。
<?php function hoge(){ eval('return "hoge called with " . func_get_arg(0);'); } echo hoge("a"); ?>
で、
Warning: func_get_arg(): Called from the global scope - no function context in ***[local\path\to\php]*** : eval()'d code(2) : eval()'d code on line 1
だ、そうです。
たぶん、クロージャで変数スコープに自由が利くようになったからやったんだろうけど、何のメリットがあってこんなことを?って感じ。どうせローカル変数は丸見えで破壊操作ありありなんだし、実行コンテキストが関数外になっても何も意味ありません。むしろ、古いコードの移植性が下がるだけ。eval文字列以外のスタティックな実装コードがバイトコード化されるとかなら、それも仕方ないけど、まあそんなの、バージョン5のうちはないでしょ。
仕方ないので、「PHPのnewはこれで置き換えだ」は、可変長引数の値をいったんローカル変数に取り込んで、evalでそのローカル変数を参照するように変えました。
<?php function newobj($class) { $seppos = strrpos($class, '/'); if($seppos !== FALSE) { require_once substr($class, 0, $seppos); $class = substr($class, $seppos + 1); } $argsvals = func_get_args(); $code = '$obj = new ' . $class . '('; for($i = 1; $i < func_num_args(); $i++) { if($i != 1) { $code .= ', '; } $code .= '$argsvals[' . $i . ']'; } $code .= ');'; eval($code); return $obj; } //便利なつかいかた newobj('./lib/my_module.php/MyClass', 1, 2, 3)->myMethod(4, 5, 6); //もちろん普通にこれでもいい require_once './lib/my_module.php'; newobj('MyClass', 1, 2, 3)->myMethod(4, 5, 6); ?>