http://blog.bz2.jp/archives/2007/11/phsh.html
尾藤さんが9月のphpカンファレンスで発表されたphshで、たとえば
<?php echo 1
が通らなくて悲しかったので、ダメダメながらなんとか通るようになるパッチを送らせていただきました。
といいつつ、実は名前空間というか変数名のコンテキスト(?)を汚しかねないことに後で気づいたんですが(とりあえず大丈夫だったっぽい)、そのへんの安全性もぱっと見でわかるように直ったパッチを当てていただきました。うーん、さすがというか、ほんとよくできてますね、これ。
exitは言語構造なんだけど
ちなみにどういうパッチだったかというと、上のechoは
eval("return echo 1;");
と解釈されるので、最初のtokenをpregで切り出してis_callable()がfalseだったら言語構造だと思って
eval("echo 1; return;");
となるようにした、というだけです。
そのなかで気づいたのが、exitって言語構造なくせに
return exit;
が通るんです。なんかおかしくないですか?
zend_language_parser.y (php5.2.4です) 見ると
185 unticked_statement: ... 210 | T_ECHO echo_expr_list ';' ... 552 expr_without_variable: ... 614 | T_UNSET_CAST expr { zend_do_cast(&$$, &$2, IS_NULL TSRMLS_CC); } 615 | T_EXIT exit_expr { zend_do_exit(&$$, &$2 TSRMLS_CC); } 616 | '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; } 617 | scalar { $$ = $1; } 618 | T_ARRAY '(' array_pair_list ')' { $$ = $3; } 619 | '`' encaps_list '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } 620 | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); }
となってました。当然ながら
1 + exit;
とか
1 - print 'aho';
もparse errorにはなりません。なんか歴史的事情とかあるんでしょうか…?
unset cast
あと、614行目のT_UNSET_CASTってなに? 初めて見た! というか "zend_do_cast(&$$, &$2, IS_NULL TSRMLS_CC);" ってもしや…
$a = (unset) 1; var_dump($a);
はい、"NULL" が表示されました。それだけ? え、まじですか??