元ネタは、某所の書籍でみた、こんなコード。
foreach($data as $key => $val) { $$key = $val; }
見た瞬間から色々気になってはいたんだけど。
ふと思って試した実験コードの内容が、思ったよりもちょっとアレゲだったので共有。
まずは、初手の実験コード。
<?php $data = array(); $data['test'] = '1'; $data['_test'] = '2'; $data['0test'] = '3'; $data['te-st'] = '4'; $data['te-st'] = '5'; foreach($data as $key => $val) { $$key = $val; } $awk = get_defined_vars(); unset($awk['_SERVER']); unset($awk['_POST']); unset($awk['_GET']); unset($awk['_FILES']); unset($awk['_COOKIE']); unset($awk['argv']); unset($awk['argc']); var_dump($awk);
意図は明白。
ん…意図を理解するために、ここを引用。
http://www.php.net/manual/ja/language.variables.basics.php
PHP の変数はドル記号の後に変数名が続く形式で表されます。 変数名は大文字小文字を区別します。
変数名は、PHPの他のラベルと同じルールに従います。 有効な変数名は文字またはアンダースコアから始まり、任意の数の文字、 数字、アンダースコアが続きます。正規表現によれば、これは次の ように表現することができます。 '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
ポイントは「有効な変数名は文字またはアンダースコアから始まり、任意の数の文字、 数字、アンダースコアが続きます」。
つまり、先頭が数字だったりハイフンが含まれてたり他の記号が含まれてたりすると「だめぽよ〜」という事。
…あれ?
んぢゃ、hashのkeyがそーゆー状態の時って、可変変数はどんな動きするんだべさ?
ってのがソースコードの意図。
で、結果。
[gallu@localhost ~]$ php t.php
array(9) {
["data"]=>
array(5) {
["test"]=>
string(1) "1"
["_test"]=>
string(1) "2"
["0test"]=>
string(1) "3"
["te-st"]=>
string(1) "5"
}
["val"]=>
string(1) "6"
["key"]=>
string(4) "this"
["test"]=>
string(1) "1"
["_test"]=>
string(1) "2"
["0test"]=>
string(1) "3"
["te-st"]=>
string(1) "5"
}
……………あれ?
エラー吐かない?
実験。
<?php $data = array(); $data['test'] = '1'; $data['_test'] = '2'; $data['0test'] = '3'; $data['te-st'] = '4'; $data['te-st'] = '5'; foreach($data as $key => $val) { $$key = $val; } var_dump( $0test ); $awk = get_defined_vars(); unset($awk['_SERVER']); unset($awk['_POST']); unset($awk['_GET']); unset($awk['_FILES']); unset($awk['_COOKIE']); unset($awk['argv']); unset($awk['argc']); var_dump($awk);
結果
[gallu@localhost ~]$ php t.php
Parse error: syntax error, unexpected '0' (T_LNUMBER), expecting variable (T_VARIABLE) or '$' in /home/furu/t.php on line 13
そうだよねぇ?
なにこれ?
「アクセスできない」変数が出来てる?
ちなみにもうちょいと実験。面倒だから部分的に切り抜くよ。
$s = '0test'; var_dump( $$s );
これだと通るんだ orz
もう一つ。
もうちょっと、ある意味深刻なケース。
var_dump( $te-st );
これ、エラー出ずに通るんだわ。ただし値が「intの0」になる。
これって「$te - st」ってパースするんだね orz
んで「$teは設定されていないからNULL」「右辺は、おそらく"文字列である st"」って解釈される。
で、算術演算子だから双方とも「一端数値にして」計算した結果、0になるんだねぇ。
……………うんすげぇや止めろ馬鹿。
ちなみに
http://www.php.net/manual/ja/language.variables.basics.php
注意: $this は特別な変数であり、ここに代入することはできません。
があるんで
$data = array(); $data['test'] = '1'; $data['_test'] = '2'; $data['0test'] = '3'; $data['te-st'] = '4'; $data['te-st'] = '5'; $data['this'] = '6';
も試したけど問題無いですよ?
面倒だから実験する気ないけど、これ、オブジェクトん中でやったらどうなるんだべさね?
…と思ったけど気になるから。
<?php class hoge { public function h($awk) { var_dump($this); foreach($awk as $key => $val) { $$key = $val; } var_dump($this); } } $data = array(); $data['test'] = '1'; $data['_test'] = '2'; $data['0test'] = '3'; $data['te-st'] = '4'; $data['te-st'] = '5'; $data['this'] = '6'; $obj = new hoge(); $obj->h($data); $awk = get_defined_vars(); unset($awk['_SERVER']); unset($awk['_POST']); unset($awk['_GET']); unset($awk['_FILES']); unset($awk['_COOKIE']); unset($awk['argv']); unset($awk['argc']); var_dump($awk);
結果
[gallu@localhost ~]$ php t.php
object(hoge)#1 (0) {
}
string(1) "6"
array(2) {
["data"]=>
array(5) {
["test"]=>
string(1) "1"
["_test"]=>
string(1) "2"
["0test"]=>
string(1) "3"
["te-st"]=>
string(1) "5"
["this"]=>
string(1) "6"
}
["obj"]=>
object(hoge)#1 (0) {
}
}
すげぇハラショー代入できちゃってるよ「ここに代入することはできません」なんだもんせめてエラーくらい吐こうよ orz
うんまぁ「嫌な予感」っておいちゃんが感じたときは大抵相応になにかあるんだけどさ。
思った以上に何かあったよ orz
上述書籍。
これをもって「簡単なテンプレートエンジン」とかって書いてあったんだけど。しょ〜じき、検証が甘すぎると思う orz
値に変な記号は使わないと思うけどさ。ハイフンは多分使う可能性が十分に考えられるし、thisとかも怖い。他にもいくつか「可能性のある」面倒毎は想像出来るし。
最低限、使うんなら「その辺を使うな」っていうか、或いはチェックロジックくらい入れておかなきゃ orz
とりあえずまぁ「可変変数」に関するおもころい(っつか恐ろしい/おぞましい)実験ができあがってしまったので、共有。