2011-01-27 67 views
23

PHP中有一种方法可以确定给定变量是否是对另一个变量的引用和/或是否被另一个变量引用?我明白,如果在php.net上给出comment这个设置$a=& $b意味着“$ a和$ b在这里是完全相等的,$ a没有指向$,我们可能无法区分检测到的”reference to“和”reference from“ b或反之亦然$ a和$ b指向相同的地方检测一个PHP变量是否是引用/引用

如果无法确定给定变量是否是引用/引用,是否有一种确定两个变量是否一致的广义方法互相参考?同样,php.net上的comment提供了一个用于进行这种比较的功能 - 尽管它是涉及编辑其中一个变量并查看其他变量是否受到类似影响的功能。如果可能,我宁愿避免这样做,因为我正在考虑的一些变量会大量使用魔法获取器/设置器。

在这种情况下请求的背景是编写一个调试功能来帮助详细查看结构。

+0

您可以检查两个变量是相互的引用:http://stackoverflow.com/a/18110347/632951 – Pacerier 2013-08-07 17:55:15

回答

6

您可以使用debug_zval_dump

function countRefs(&$var) { 
    ob_start(); 
    debug_zval_dump(&$var); 
    preg_match('~refcount\((\d+)\)~', ob_get_clean(), $matches); 
    return $matches[1] - 4; 
} 

$var = 'A'; 
echo countRefs($var); // 0 

$ref =& $var; 
echo countRefs($var); // 1 

这虽然不会了,因为PHP 5.4的,因为它们通过参考支持删除通话时间通工作,并可以在较低的版本抛出E_STRICT级别的错误。

如果你想知道,上述函数中的-4来自哪里:你告诉我......我通过尝试得到它。在我眼中,它应该只有3个(变量,我的函数中的变量,变量传递给zend_debug_zval),但我不太擅长PHP内部,它似乎在途中创建了另一个参考;)

1

编辑: 看来我已经回答了这个问题“是否有可能检查两个变量引用在内存中相同的价值”而不是实际的问题问。 :P


只要'普通'变量的答案是'不'。

只要对象去 - 也许。

所有对象默认由引用处理。另外每个物体都有它的序列号,你可以看到它的时候你可以看到它var_dump()它。

>> class a {}; 
>> $a = new a(); 
>> var_dump($a); 

object(a)#12 (0) { 
} 

如果你能得到某种方式这个#,你可以有效地比较这两个变量,看看他们是否指向同一个对象。问题是如何得到这个数字。 var_export()不会返回它。我在Reflection课程中没有看到任何问题。这在我脑海

有一件事是使用输出缓冲+正则表达式

+0

捕获`var_export输出($变量,TRUE)`然后一个小正则表达式应该捕获数字 – 2011-01-27 14:54:39

+0

@ KristofferSall-Storgaard:只适用于`print_r()` – calcinai 2016-10-19 13:07:37

1

xdebug_debug_zval()为顶点。现在,这是真正知道您是否可以确定有关变量zval的所有内容的唯一方法。

所以这里有一对夫妇的辅助功能,以确定一些有用的信息:

function isRef($var) { 
    $info = getZvalRefCountInfo($var); 
    return (boolean) $info['is_ref']; 
} 
function getRefCount($var) { 
    $info = getZvalRefCountInfo($var); 
    return $info['refcount']; 
} 
function canCopyOnWrite($var) { 
    $info = getZvalRefCountInfo($var); 
    return $info['is_ref'] == 0; 
} 
function canReferenceWithoutCopy($var) { 
    $info = getZvalRefCountInfo($var); 
    return $info['is_ref'] == 1 || $info['refcount'] == 1; 
} 

function getZvalRefCountInfo($var) { 
    ob_start(); 
    xdebug_debug_zval($var); 
    $info = ob_get_clean(); 
    preg_match('(: \(refcount=(\d+), is_ref=(\d+)\))', $info, $match); 
    return array('refcount' => $match[1], 'is_ref' => $match[2]); 
} 
一些样品变量

所以:

$a = 'test'; 
$b = $a; 
$c = $b; 
$d =& $c; 
$e = 'foo'; 

我们可以测试一个变量的引用:

isRef('a'); // false 
isRef('c'); // true 
isRef('e'); // false 

我们可以得到链接到zval的变量的数量(不一定是引用,可以是对于写入时复制):

getRefCount('a'); // 2 
getRefCount('c'); // 2 
getRefCount('e'); // 1 

我们可以测试我们可以写入时复制(没有副本进行内存复制):

canCopyOnWrite('a'); // true 
canCopyOnWrite('c'); // false 
canCopyOnWrite('e'); // true 

我们可以测试我们可以做而不复制的zval的引用:现在

canReferenceWithoutCopy('a'); // false 
canReferenceWithoutCopy('c'); // true 
canReferenceWithoutCopy('e'); // true 

而且,我们可以检查,如果一个变量引用本身通过一些魔法:

function isReferenceOf(&$a, &$b) { 
    if (!isRef('a') || getZvalRefCountInfo('a') != getZvalRefCountInfo('b')) { 
     return false; 
    } 
    $tmp = $a; 
    if (is_object($a) || is_array($a)) { 
     $a = 'test'; 
     $ret = $b === 'test'; 
     $a = $tmp; 
    } else { 
     $a = array(); 
     $ret = $b === array(); 
     $a = $tmp; 
    } 
    return $tmp; 
} 

这有点不好意思,因为我们无法确定其他符号引用相同的zval(只有其他符号引用)。因此,这基本上检查是否$a是一个参考,并且如果$a$b都具有相同的引用计数和引用标志设置。然后,它会更改一个以检查其他更改(表明它们是相同的参考)。

5

全部工作示例:

function EqualReferences(&$first, &$second){ 
    if($first !== $second){ 
     return false; 
    } 
    $value_of_first = $first; 
    $first = ($first === true) ? false : true; // modify $first 
    $is_ref = ($first === $second); // after modifying $first, $second will not be equal to $first, unless $second and $first points to the same variable. 
    $first = $value_of_first; // unmodify $first 
    return $is_ref; 
} 

$a = array('foo'); 
$b = array('foo'); 
$c = &$a; 
$d = $a; 

var_dump(EqualReferences($a, $b)); // false 
var_dump(EqualReferences($b, $c)); // false 
var_dump(EqualReferences($a, $c)); // true 
var_dump(EqualReferences($a, $d)); // false 
var_dump($a); // unmodified 
var_dump($b); // unmodified