2010-06-30 70 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] =>) 
相关问题