代码之家  ›  专栏  ›  技术社区  ›  lepe

php:检查对象/数组是否为引用

  •  15
  • lepe  · 技术社区  · 14 年前

    不好意思问,太晚了,我想不出办法…有人能帮忙吗?

    $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显示:

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

    这意味着“用户”是一个参考。

    我想这样做:

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

    主要目标是复制数组而不使用任何引用。

    有可能吗?

    谢谢您。

    5 回复  |  直到 10 年前
        1
  •  7
  •   Chris    14 年前

    您可以通过复制数组来测试多维数组中的引用,然后依次更改和测试每个条目:

    $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[用户] 它在 房间[用户] .

        2
  •  3
  •   Mark Baker    14 年前

    我能管理的最好方法是对两个变量进行测试,以确定其中一个变量是否是对另一个变量的引用:

    $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可以使它始终是引用

        3
  •  1
  •   RobertPitt    14 年前

    可能是递归的。

    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
  •  1
  •   TomX    14 年前
    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对象和数组。

        5
  •  0
  •   diyism    10 年前

    如果要除去递归元素:

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