PHP: проверить, является ли объект / массив ссылкой - PullRequest
15 голосов
/ 30 июня 2010

Жаль спрашивать, уже поздно, и я не могу придумать, как это сделать ... кто-нибудь может помочь?

$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]);
}

Основная цель - скопировать массив БЕЗ любых ссылок.

Это возможно?

Спасибо.

Ответы [ 5 ]

7 голосов
/ 30 июня 2010

Вы можете проверить ссылки в многомерном массиве, сделав копию массива, а затем изменив и протестировав каждую запись по очереди:

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

3 голосов
/ 30 июня 2010

Лучшее, чем я могу управлять, - это проверка двух переменных, чтобы определить, является ли одна из них ссылкой на другую:

$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 делает его всегда ссылкой

1 голос
/ 18 декабря 2010
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 объектами и массивами.

1 голос
/ 30 июня 2010

что-то рекурсивное, может быть.

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;
}
0 голосов
/ 18 июля 2014

, если вы хотите избавиться от рекурсивных элементов:

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