我能知道一个变量是否是根据它的值和名称在全局空间中定义的吗


Can I find out if a variable is defined in the global space based on its value and name?

我知道变量名,比如$var及其值。

如果我检查isset($GLOBALS[$var_name]) && $GLOBALS[$var_name] == $var,即使变量不是真正的全局变量,但恰好与现有全局变量具有相同的名称和值,我也可能得到正结果:(

我需要它作为我正在构建的调试函数,以显示有关传递的变量类型的更多信息。

我还可以知道一个变量是否是静态的吗?:)

ps:反射对我没有帮助。它只能获取对象或函数的信息。。。

如果变量是彼此的引用(这基本上是您想要检查的),它们将使用相同的zval。因此,这里有一种稍微令人讨厌但会奏效的方法:

<?php
    function vars_are_referenced (&$var1, &$var2) {
        // What we are doing *will* throw an error (I said it was nasty ;-) )
        $oldER = error_reporting();
        $oldDE = ini_get('display_errors');
        error_reporting(0);
        ini_set('display_errors', 0);
        // We need to use output buffering, we don't want to break any existing
        // buffering so we cache the contents of the buffer
        $oldBuffer = ob_get_length() ? ob_get_clean() : NULL;
        // If the values are not identical, definitely not a match
        if ($var1 !== $var2) return FALSE;
        // Now we inspect the zval of $var1
        ob_start();
        debug_zval_dump(&$var1);
        preg_match('/'brefcount'(('d+)')(?:'b|$)/', ob_get_clean(), $matches);
        $var1RefCountBefore = (int) $matches[1];
        // If they are the same, this will increase the refcount
        $temp = &$var2;
        // Inspect the zval of $var1 again
        ob_start();
        debug_zval_dump(&$var1);
        preg_match('/'brefcount'(('d+)')(?:'b|$)/', ob_get_clean(), $matches);
        $var1RefCountAfter = (int) $matches[1];
        // If refcount is now greater, they are the same
        $result = $var1RefCountAfter > $var1RefCountBefore;
        // Repopulate the output buffer if necessary
        if ($oldBuffer !== NULL) {
            ob_start();
            echo $oldBuffer;
        }
        // Turn error reporting back to correct level
        error_reporting($oldER);
        ini_set('display_errors', $oldDE);
        return $result;
    }
    function test_ref_fail () {
        $a = 1;
        $var_name = 'a';
        var_dump(vars_are_referenced($GLOBALS['a'], $a));
    }
    function test_ref_success_1 () {
        global $a;
        $var_name = 'a';
        var_dump(vars_are_referenced($GLOBALS['a'], $a));
    }
    function test_ref_success_2 (&$a) {
        $var_name = 'a';
        var_dump(vars_are_referenced($GLOBALS['a'], $a));
    }
    $a = 1;
    $b = &$a;
    var_dump(vars_are_referenced($a, $b));
    test_ref_fail();
    test_ref_success_1();
    test_ref_success_2($a);

这将是最好的方法(通过检查zval),但正如我相信你可以看到的,对于PHP中目前可用的函数来说,这不是一个很好的方法。它将引发错误,因为使debug_zval_dump()像我们需要的那样工作所需的调用时间传递引用。它将在PHP中导致致命错误>=5.4,因为调用时间传递参考已被删除。

所以这里有另一种方法-我不喜欢,因为它涉及修改变量,但它不应该破坏任何东西,至关重要的是,它不会引发任何错误,并且会在任何地方工作:

<?php
    function vars_are_referenced (&$var1, &$var2) {
        // If the values are not identical, definitely not a match
        if ($var1 !== $var2) return FALSE;
        // Make a copy of the old value
        $oldVal = $var1;
        // Get a new value we can assign that is different to the old value
        $newVal = ($oldVal === 1) ? 2 : 1;
        // Assign the value to $var1
        $var1 = $newVal;
        // See if $var2 has changed
        $result = $var1 === $var2;
        // Put the value of $var1 right again
        $var1 = $oldVal;
        return $result;
    }

这里有一个助手函数(它将与上面的vars_are_referenced()定义中的任何一个一起工作),根据变量的名称(字符串)和变量本身来确定变量是否是全局的:

<?php
    function var_is_global ($name, &$var) {
        return vars_are_referenced($GLOBALS[$name], $var);
    }

我想不出一种方法来准确地检查任意变量在对象上下文之外是否是静态的。

eval()如何处理全局语句?

function isglobal($name)
{
    return eval('global $'. $name .'; return isset($'. $name .');');
}

但是,请注意正确转义要检查的名称。

您需要了解get_defined_vars()函数,该函数返回所有定义变量的数组。

var_dump(get_defined_vars())

但是,如果您想正确地执行此操作,请查看Xdebug,在那里您不仅可以预览集变量,还可以跟踪它们。点击这里了解更多信息。