2

我知道变量名,like$var和它的值。

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

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

我还可以找出变量是否是静态的吗?:)

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

4

3 回答 3

7

如果变量是彼此的引用(这本质上是您想要检查的),它们将使用相同的 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);
    }

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

于 2012-07-18T15:43:31.777 回答
3

您想看看get_defined_vars()函数,它返回一个包含所有已定义变量的数组。

var_dump(get_defined_vars())

但是如果你想正确地做到这一点,看看 Xdebug,你不仅可以预览设置变量,还可以跟踪它们。点击这里获取更多信息。

于 2012-07-18T15:41:50.857 回答
3

eval()'ing 全局语句怎么样?

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

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

于 2012-07-18T15:38:52.900 回答