PHP: check if object/array is a reference
Sorry to ask, its late and I can't figure a way to do it... anyone can help?
$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 $room shows:
...
'users' => &
...
开发者_开发问答Which means "users" is a reference.
I would like to do something like this:
foreach($room as $key => $val) {
if(is_reference($val)) unset($room[$key]);
}
The main goal is to copy the array WITHOUT any references.
Is that possible?
Thank you.
You can test for references in a multi-dimensional array by making a copy of the array, and then altering and testing each entry in turn:
$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);
With your example data, $room['furniture']
and $roomCopy['furniture']
will be separate arrays (as $roomCopy
is a copy of $room
), so adding a new key to one won't affect the other. But, $room['users']
and $roomCopy['users']
will be references to the same $users
array (as it's the reference that's copied, not the array), so when we add a key to $roomCopy['users']
it is visible in $room['users']
.
The best I can manage is a test of two variables to determine if one is a reference to the other:
$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);
but I doubt if it's much help
Really dirty method (not well tested either):
$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));
To use this last method in your code, you'd need to do something like:
foreach($room as $key => $val) {
if(isReference($room[$key])) unset($room[$key]);
}
because $val is never a reference as it's a copy of the original array element; and using &$val makes it always a reference
something recursive maybe.
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;
}
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;
}
//-------------------------------------------------------------------------------------------
This works with HUDGE objects and arrays.
if you want to get rid of recursive elements:
<?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);
?>
output:
stdClass Object ( [a] => 3 [b] => stdClass Object *RECURSION* )
stdClass Object ( [a] => 3 [b] => )
精彩评论