[PHP-users 9578] Re: 関数でスーパーグローバル変数を可変変数で取得するには

Masaki Fujimoto php-users@php.gr.jp
Wed, 28 Aug 2002 10:59:40 +0900


ふじもとです。

On Tue, 27 Aug 2002 20:45:28 +0900
Toshiyuki Kajii <mikoto@camino.nissan.ne.jp> wrote:
-snip-
> スーパーグローバルな変数であっても、可変変数で扱う場合にはglobal宣言
> しないといけないのでしょうか。

現状ではそういうことになっております:(

> この理由について、ご教示いただけるとありがたいです。

まず、「なぜ関数内で可変変数を用いてスーパーグローバル変数を使用するとき
はglobal宣言が必要か」という点についてですが、これは簡単に言うと「その変
数がスーパーグローバルかどうかはコンパイル時に決定されている」からです。
なので、現状では可変変数のように実行時に初めてその変数名が分かる場合には、
それがスーパーグローバルかどうかというチェックは行われていません。

もうちょっと具体的に書くと、

(1) 実行開始時にmain/main.c:php_module_startup()から
    zend_register_auto_global()が呼び出されスーパーグローバルとして扱わ
    れる変数名が登録されます。
(2) スクリプトのコンパイル時にparserから呼び出される
    Zend/zend_compile.c:fetch_simple_variable_ex()は、その変数名が(1)で
    スーパーグローバルとして登録された名前かどうかをチェックして、必要な
    ら強制的にグローバル変数として扱います。

上記に挙げた関数やzend_language_parser.yをご覧いただければ「あぁ、そうい
うことか」とお分かりいただけるかと思います。

また、「なぜこんな仕様になっているか」という点に関しては僕にもよくわかり
ません。ただ、

http://bugs.php.net/bug.php?id=15810

ここでFeature/Change Requestとして上がっているのでおいおい修正される可能
性はあります。一応quick patchを作ってみたので試してみたい場合はどうぞ。
ただ、このパッチでは明らかにパフォーマンスが低下するのでもうちょっと改善
してから本家の人々に聞いてみます。

ちなみに安定性は保証の限りではありません:)

Index: zend_execute.c
===================================================================
RCS file: /repository/Zend/zend_execute.c,v
retrieving revision 1.305
diff -u -r1.305 zend_execute.c
--- zend_execute.c      24 Aug 2002 20:49:39 -0000      1.305
+++ zend_execute.c      28 Aug 2002 01:49:10 -0000
@@ -533,7 +533,13 @@

        switch (opline->op2.u.fetch_type) {
                case ZEND_FETCH_LOCAL:
-                       target_symbol_table = EG(active_symbol_table);
+                       /* check if runtime auto globals */
+                       if (varname->type == IS_STRING
+                               && zend_hash_exists(CG(auto_globals), varname->value.str.val, varname->value.str.len+1)) {
+                               target_symbol_table = &EG(symbol_table);
+                       } else {
+                               target_symbol_table = EG(active_symbol_table);
+                       }
                        break;
                case ZEND_FETCH_GLOBAL:
                        if (opline->op1.op_type == IS_VAR) {

--
藤本 真樹

アストラザスタジオ
fujimoto@studio.co.jp
fujimoto@php.net