おぎろぐはてブロ

なんだかんだエンジニアになって10年以上

php.ini-recommendedで、variables_orderがGPCSである理由と、PHP5のauto_globals_jit

遅ればせながら関連ネタ。

ライブラリの類で$_ENVを使うのはやめてgetenv()を使いましょうって思った。

getenv()推進キャンペーンを考えた - 絶品ゆどうふのタレ

これには同感。recommendedが variables_order="GPCS" である以上、多くの環境*1で手を加えずに動かせるようにするためには、それがいいか悪いかは関係なく、これを基準として動くアプリケーションを書いた方がいいと思います。

なぜ、variables_orderに "E" が含まれないのか

recommended = オススメ設定なのだけれど、どういう理由なのか。これは、php.ini-recommendedのコメントにあるように、パフォーマンス対策とのこと。

; - variables_order = "GPCS" [Performance]
; The environment variables are not hashed into the $_ENV. To access
; environment variables, you can use getenv() instead.

http://cvs.php.net/viewvc.cgi/php-src/php.ini-recommended?revision=1.179.2.11.2.23&view=markup

これは簡単な話で、作るのにコストがかかるから。環境変数を取ってきて、スーパーグローバル変数の配列に詰めないといけない。使わないのだったら無駄になってしまいます。
ただ、逆に環境変数を多用して、getenv()を大量にコールすることになると、作られた配列の参照よりも、逆に時間がかかってしまうので、こちらがパフォーマンスの面でよいとは一概には言えない。だけれど、普通のウェブアプリでそういうことはしないよねー、ということで E が含まれてないのではと思います。

これは突き詰めると、EGPCSの残りのものにも同じことが言えます。Webサーバ上で動かすことが基本となるので、さすがに GPCあたりを外してしまうのはアレだけれども、$_SERVERは、使わないことが無いこともないので、前にも書いたOmniTIのGeorge Schlossnagle氏のZend Conferenceで発表したスライド(PDF)の29ページにあるように、

variables_order = "GPC"

と、Sすら外してしまうのもアリです。そして、この値もgetenv()から取得することができます。(PHPのgetenv()は、最初にSAPI側の用意するsapi_getenv()を叩いて、該当しなければ普通のgetenv()をコールしています。Apacheだと、sapi_getenv()で取れる値は、$_SERVERと同じ。他は知らない)

コストがかかるというのはPHP4までの話

上のように使わないものを作るのはイケてないねー、ということで、PHP5からは、参照されたときに始めてスーパーグローバル変数が作成されるJIT (Just in Time)の仕組みが採用されています。すなわち使われなければ生成されることもありませんので、使わなくて無駄ということがなくなります。デフォルトで有効です。
PHP4と仕組みが異なることから、無効にすることもでき、その設定項目が [http://php.net/ini.core#ini.auto-globals-jit:title=auto_globals_jit]。Onであれば有効に、Offなら無効になり、Offの場合はJITではなく、従来と同じようにリクエスト初期化フェーズでvariables_orderに指定された各グローバル変数が生成されます。
普通にPHPスクリプトで扱っている場合は、何も動作の変化は感じられないのですが、お行儀の悪いExtensionなんかがいるとうまく値を取れなくなることがあります。過去、APCがそういう状態だったようです。(PHP :: Bug #56445 :: APC - superglobals empty once script is cached)

名前 デフォルト 変更の可否
auto_globals_jit "1" PHP_INI_PERDIR

で、これは php.ini-recommended でもOnです。

; When enabled, the SERVER and ENV variables are created when they're first
; used (Just In Time) instead of when the script starts. If these variables
; are not used within a script, having this directive on will result in a
; performance gain. The PHP directives register_globals, register_long_arrays,
; and register_argc_argv must be disabled for this directive to have any affect.
auto_globals_jit = On

http://cvs.php.net/viewvc.cgi/php-src/php.ini-recommended?revision=1.179.2.11.2.23&view=markup

結論

PHP5においては、recommendedの設定だと、auto_globals_jitが有効なので、$_ENVが含まれていることによるパフォーマンスへの影響はないんでないかと思います。
けど、そういう環境がある以上、$_ENVの利用は避けるといいです。


詳しい実装については気が向いたらまとめる。

*1:個人的には、ずっと$_ENVも$_SERVERも無い環境に触れてきたので、使わないのが染みついてます