我能否根据其值和名称找出变量是否在全局空间中定义的? [英] Can I find out if a variable is defined in the global space based on its value and name?

查看:116
本文介绍了我能否根据其值和名称找出变量是否在全局空间中定义的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

我需要这个函数来创建一个调试函数,以显示有关所传递变量类型的更多信息。



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



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

解决方案

如果变量是相互引用的(这实质上就是你想要检查的),他们将使用相同的zval。因此,这里有点讨厌,但会工作,做到这一点:

 <?php 

函数vars_are_referenced(& $ var1,& $ var2){

//我们正在做什么*将*抛出一个错误(我说它很讨厌;-))
$ oldER = error_reporting();
$ oldDE = ini_get('display_errors');
error_reporting(0);
ini_set('display_errors',0);

//我们需要使用输出缓冲,我们不想破坏任何现有的
//缓冲,所以我们缓存缓冲区的内容
$ oldBuffer = ob_get_length( )? ob_get_clean():NULL;

//如果值不相同,那么绝对不匹配
if($ var1!== $ var2)return FALSE;

//现在我们检查$ var1
ob_start()的zval;
debug_zval_dump(& $ var1);
preg_match('/ \brefcount \((\ d +)\)(?: \b | $)/',ob_get_clean(),$ matches);
$ var1RefCountBefore =(int)$ matches [1];

//如果它们相同,则会增加refcount
$ temp =& $ var2;

//再次检查$ var1的zval
ob_start();
debug_zval_dump(& $ var1);
preg_match('/ \brefcount \((\ d +)\)(?: \b | $)/',ob_get_clean(),$ matches);
$ var1RefCountAfter =(int)$ matches [1];

//如果refcount现在更大,它们是相同的
$ result = $ var1RefCountAfter> $ var1RefCountBefore;

//根据需要重新配置输出缓冲区
if($ oldBuffer!== NULL){
ob_start();
echo $ oldBuffer;
}

//将错误报告返回到正确的级别
error_reporting($ oldER);
ini_set('display_errors',$ oldDE);

返回$ result;

}

函数test_ref_fail(){
$ a = 1;
$ var_name ='a';
var_dump(vars_are_referenced($ GLOBALS ['a'],$ a));
}

函数test_ref_success_1(){
global $ a;
$ var_name ='a';
var_dump(vars_are_referenced($ GLOBALS ['a'],$ a));


函数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值不相同,如果($ var1!== $ var2)返回FALSE,则绝对不匹配
;

//复制旧值
$ oldVal = $ var1;

//获取我们可以赋值的新值,它与旧值不同
$ newVal =($ oldVal === 1)? 2:1;

//将值赋给$ var1
$ var1 = $ newVal;

//查看$ var2是否已更改
$ result = $ var1 === $ var2;

//将$ var1的值再次赋值
$ var1 = $ oldVal;

返回$ result;






这是一个辅助函数(它可以与任何上面的 vars_are_referenced()定义)根据变量名称作为字符串和变量本身确定变量是否是全局变量:

 <?php 

函数var_is_global($ name,& $ var){
return vars_are_referenced($ GLOBALS [$ name],$ var);
}

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


I know the variable name, like $var and its value.

If I check for isset($GLOBALS[$var_name]) && $GLOBALS[$var_name] == $var I may get a positive result even if the variable is not really global, but happens to have the same name and value as an existing global variable :(

I need this for a debug function that I'm building, to display more info about the type of the variable that was passed.

Could I also find out if a variable is static? :)

ps: reflection doesn't help me.. It can only get info for objects or functions...

解决方案

If the variables are references to each other (which is essentially what you want to check), they will use the same zval. Therefore, here is a slightly nasty, but will work, way to do it:

<?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);

This would be the best way to do it (by inspecting the zval), but as I'm sure you can see, this is not a pretty method with the functions currently available in PHP. It will raise errors because of the call-time pass-by-reference that is required to make debug_zval_dump() work like we need it to. It will cause a fatal error in PHP >= 5.4 because call-time pass-by-reference has been removed.

So here is the other way to do it - which I don't like, because it involves modifying the variables, but it shouldn't break anything and crucially, wont raise any errors and will work everywhere:

<?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;

    }

Here is a helper function (which will work with either of the vars_are_referenced() definitions above) to determine specifically if a variable is global, based on the name of the variable as a string and the variable itself:

<?php

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

I can't think of a way to accurately check if an arbitrary variable is static outside the context of an object.

这篇关于我能否根据其值和名称找出变量是否在全局空间中定义的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆