2011-01-27 72 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