2010-06-30 71 views
15

對不起,請問,它遲到了,我想不出辦法做到這一點......任何人都可以提供幫助嗎?PHP:檢查對象/數組是否是一個參考

$users = array(
    array(
     "name" => "John", 
     "age" => "20" 
    ), 
    array(
     "name" => "Betty", 
     "age" => "22" 
    ) 
); 

$room = array(
    "furniture" => array("table","bed","chair"), 
    "objects" => array("tv","radio","book","lamp"), 
    "users" => &$users 
); 

的var_dump $房顯示:

... 
'users' => & 
... 

這意味着 「用戶」 是一個參考。

我願做這樣的事情:

foreach($room as $key => $val) { 
    if(is_reference($val)) unset($room[$key]); 
} 

主要目標是到陣列複製沒有任何引用。

這可能嗎?

謝謝。

+2

第一個註釋說明它是如何做到:http://www.php.net/manual /en/language.references.spot.php – pritaeas 2010-06-30 09:59:06

+0

你想要沒有用戶密鑰的$房間,對吧?有沒有其他的參考資料,還是隻有用戶? – Gordon 2010-06-30 10:05:49

+0

是的。問題是我有一個很大的數組,裏面有很多交叉引用。我想得到它的一部分,但沒有參考。所以簡而言之,關鍵可能是可變的。我現在很懶惰,我不想追溯所有當前和未來的參考。 – lepe 2010-06-30 10:18:27

回答

7

您可以通過數組的一個副本,然後改變和測試反過來每個條目測試在一個多維數組引用:

$roomCopy = $room; 
foreach ($room as $key => $val) { 
    $roomCopy[$key]['_test'] = true; 
    if (isset($room[$key]['_test'])) { 
    // It's a reference 
    unset($room[$key]); 
    } 
} 
unset($roomCopy); 

有了您的數據。例如,$room['furniture']$roomCopy['furniture']會單獨的陣列(因爲$roomCopy$room的副本),所以向其中添加一個新密鑰不會影響另一個。但是,$room['users']$roomCopy['users']將引用同一個$users數組(因爲它是複製的引用,而不是數組),所以當我們向$roomCopy['users']添加密鑰時,它在$room['users']中可見。

+1

骯髒的解決方案,但創意... +1 – lepe 2010-06-30 10:15:40

+1

分析由pritaeas給出的鏈接,它導致幾乎相同的解決方案,但這更多的擴展(我仍然喜歡這個減少編譯)。 – lepe 2010-06-30 10:26:38

1

可能是遞歸的。

function removeReferences($inbound) 
{ 
    foreach($inbound as $key => $context) 
    { 
     if(is_array($context)) 
     { 
      $inbound[$key] = removeReferences($context) 
     }elseif(is_object($context) && is_reference($context)) 
     { 
      unset($inbound[$key]); //Remove the entity from the array. 
     } 
    } 
    return $inbound; 
} 
+4

除了'is_reference'不存在。這就是他之後;) – Chris 2010-06-30 10:11:07

+0

是啊我的壞,我張貼,並意識到試圖找到一個解決方案,但克里斯史密斯的骯髒的方法似乎是唯一的方法 – RobertPitt 2010-06-30 11:46:43

3

我可以管理的最好的是兩個變量的測試,以確定是否一個是另一個的引用:

$x = "something"; 
$y = &$x; 
$z = "something else"; 

function testReference(&$xVal,&$yVal) { 
    $temp = $xVal; 
    $xVal = "I am a reference"; 
    if ($yVal == "I am a reference") { echo "is reference<br />"; } else { echo "is not reference<br />"; } 
    $xVal = $temp; 
} 

testReference($x,$y); 
testReference($y,$x); 

testReference($x,$z); 
testReference($z,$x); 

testReference($y,$z); 
testReference($z,$y); 

但我懷疑它是否太大的幫助

實在太髒方法(沒有經過很好的測試):

$x = "something"; 
$y = &$x; 
$z = "something else"; 

function isReference(&$xVal) { 
    ob_start(); 
    debug_zval_dump(&$xVal); 
    $dump = ob_get_clean(); 
    preg_match('/refcount\((\d*)\)/',$dump,$matches); 
    if ($matches[1] > 4) { return true; } else { return false; } 
} 

var_dump(isReference($x)); 
var_dump(isReference($y)); 
var_dump(isReference($z)); 

要在你的代碼中使用這最後一種方法,你需要做一些例如:

foreach($room as $key => $val) { 
    if(isReference($room[$key])) unset($room[$key]); 
} 

因爲$ val永遠不是引用,因爲它是原始數組元素的副本;並使用& $ VAL使得它始終是一個參考

+0

對於簡單的值(字符串,整型等),您的第一個方法可以工作(作爲它基本上是Chris發佈的),但不適用於陣列。第二種方法有趣的是使用debug_zval_dump「refcount」。但恕我直言,它將與從var_dump結果中解析出「&」幾乎相同,區別在於使用此方法可以獲得引用的數量。 順便說一句,將引用作爲參數傳遞給函數已被棄用。它應該是:debug_zval_dump($ xVal); – lepe 2010-07-01 00:46:56

+0

關於pass-by-reference/pass-by-value,debug_zval_dump()是相當奇怪的,並且在專用於該主題的文檔中有一整塊。但是,除非您使用傳遞引用的棄用形式,否則debug_zval_dump()似乎適用於副本(具有1的refcount),而不是變量本身......它就像是舊的傳遞方法的遺忘痕跡以參考 – 2010-07-01 07:42:27

+0

哦,我明白了。有趣... – lepe 2010-07-02 00:43:12

1
function var_reference_count(&$xVal) { 
    $ao = is_array($xVal)||is_object($xVal); 

    if($ao) { $temp= $xVal; $xVal=array(); } 

    ob_start();   
    debug_zval_dump(&$xVal); 
    $dump = ob_get_clean(); 

    if($ao) $xVal=$temp; 

    preg_match('/refcount\((\d*)\)/',$dump,$matches); 
    return $matches[1] - 3; 
} 
//------------------------------------------------------------------------------------------- 

這適用於HUDGE對象和數組。

如果你想
0

擺脫遞歸元素:

<?php 
$arr=(object)(NULL); $arr->a=3; $arr->b=&$arr; 
//$arr=array('a'=>3, 'b'=>&$arr); 
print_r($arr); 

$arr_clean=eval('return '.strtr(var_export($arr, true), array('stdClass::__set_state'=>'(object)')).';'); 
print_r($arr_clean); 
?> 

輸出:

stdClass Object ([a] => 3 [b] => stdClass Object *RECURSION*) 
stdClass Object ([a] => 3 [b] =>)