PHP get_defined_vars()不会在函数内打印超全局

时间:2017-12-05 15:59:35

标签: php

我正在调试一些遗留代码,并希望使用预构建的函数,它本质上是get_defined_vars()的包装器。

直接在调用文件中运行此代码会按预期打印一组变量:

print_r(get_defined_vars());

但是,在我的函数的简化版本中包装它会打印一个空数组:

function debugAllVars() {
    print_r(get_defined_vars());
}
debugAllVars();

无论范围如何,我都期望"超全球"诸如$_POST之类的变量将出现在输出中。

为什么输出完全为空?

2 个答案:

答案 0 :(得分:4)

get_defined_vars()打印"符号表中的所有变量"它被调用的范围。当您尝试将其包装为debugAllVars时,您将引入一个新的范围,该范围具有新的符号表。

对于像这样的独立函数,符号表包含:

  • 功能参数
  • 使用global关键字
  • 导入当前范围的所有全局变量
  • 当前范围内使用static关键字声明的任何static variables(即使未分配值)
  • 通过为其分配值隐式声明的任何变量
  • 通过引用它们隐式声明的任何变量(例如$foo = &$bar将隐式声明$bar如果尚未定义; $foo = $bar则不会)

值得注意的是,此列表包含超级全局,例如$_GET$_POST$GLOBALS。如果你在全局范围内运行get_defined_vars()(即在任何函数之外),你会看到这些 存在于那里的符号表中,这也是魔术变量$GLOBALS指着。那么,为什么它们并不存在于每个范围内,如果它们不存在,我们如何使用它们?

为此,我们需要深入了解实现的内部,其中这些变量被称为" auto-globals"而不是" superglobals"。

为什么的答案是绩效:"自动全球"的天真实施将是一个行为,好像每个函数自动在顶部读数global $_GET, $_POST, ...;有一条线。但是,这意味着在运行每个函数之前将所有这些变量复制到符号表中,即使它们没有被使用。

相反,这些变量在编译器中是特殊的,同时将PHP代码转换为内部"操作码"由执行代码的VM使用。

使用a source code browser,我们可以看到它是如何工作的。

关键功能是zend_is_auto_global中的zend_compile.c(取自当前master,实际上是PHP 7.2):

zend_bool zend_is_auto_global(zend_string *name) /* {{{ */
{
    zend_auto_global *auto_global;

    if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
        if (auto_global->armed) {
            auto_global->armed = auto_global->auto_global_callback(auto_global->name);
        }
        return 1;
    }
    return 0;
}

这里,name是变量的名称,CG表示"编译器全局",因此该函数的主要工作是说"如果给定的变量名称在名为auto_globals的编译器全局哈希中,返回1"。对auto_global_callback的附加调用允许变量为"延迟加载",并且仅在首次引用时填充。

zend_compile_simple_var_no_cv

中,该函数的主要用法似乎是有条件的
if (name_node.op_type == IS_CONST && 
    zend_is_auto_global(Z_STR(name_node.u.constant))) {

    opline->extended_value = ZEND_FETCH_GLOBAL;
} else {
    opline->extended_value = ZEND_FETCH_LOCAL;
}

换句话说,如果您引用的变量名称位于超全局列表中,则编译器会将操作码切换为不同的模式,以便在执行时,它会全局查找变量而不是本地变量。

答案 1 :(得分:3)

get_defined_vars将所有变量定义为在其调用的范围内。您的debugAllVars函数引入了新的范围,因此{{1最多会给你get_defined_vars中的所有变量。它无法从调用者的范围中为您提供变量。

另见Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?