15

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.

8
  • 2
    The first comment shows how it can be done: php.net/manual/en/language.references.spot.php Commented Jun 30, 2010 at 9:59
  • You want $room without the users key, right? Can there be other references or would it only be users? Commented Jun 30, 2010 at 10:05
  • Yea. The problem is that I have a large size array with many cross-references inside of it. And I want to get a part of it but without the references. So in short, the key may be variable. I'm kind of lazy now and I don't want to track back all the current and future references. Commented Jun 30, 2010 at 10:18
  • BTW.. I will try the example that pritaeas posted... Commented Jun 30, 2010 at 10:19
  • What about references at a deeper level within the array, do those need to be culled? Commented Jun 30, 2010 at 12:31

5 Answers 5

7

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'].

Sign up to request clarification or add additional context in comments.

2 Comments

Kind of dirty solution but creative... +1
Analyzing the link given by pritaeas, it results to be almost the same solution as this one but more extended (I still prefer this reduced compilation).
3

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

2 Comments

For simple values (string,int,etc.) your first method could work (as it is basically what Chris posted), but not for arrays. The second method its interesting the use of debug_zval_dump "refcount". But IMHO it would be almost the same as parsing out the "&" from var_dump result, with the difference that with this method it is possible to obtain the number of references. BTW, passing references, as argument, into functions is deprecated. It should be: debug_zval_dump($xVal);
debug_zval_dump() is rather weird as regards pass-by-reference/pass-by-value, and there's a whole block in the documentation dedicated to that topic. However, unless you use the deprecated form of pass-by-reference, debug_zval_dump() seems to work on a copy (with a refcount of 1) rather than the variable itself... it's like a forgotten vestige of the old method of pass-by-reference
1

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;
}

2 Comments

Except is_reference doesn't exist. That's what he's after ;)
yea my bad, i posted that and realised at tried to find a solution but Chris Smith's Dirty method seems the only way
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;
}
//-------------------------------------------------------------------------------------------

This works with HUDGE objects and arrays.

Comments

0

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] => ) 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.