【问题标题】:Can somebody explain difference between this 2 reference usages in PHP?有人可以解释 PHP 中这两种参考用法之间的区别吗?
【发布时间】:2012-10-04 21:49:04
【问题描述】:

下面的代码说明了 PHP 引用的奇怪行为:

<?php

function this_works()
{
    $root = array('name'=>'root', 'children'=>array());
    $level_1 = array('name'=>'level_1', 'children'=>array());
    $item1 = array('name'=>'level_2_1', 'children'=>array());
    $item2 = array('name'=>'level_2_2', 'children'=>array());

    $croot = &$root;

    $croot['children'][] = &$level_1;

    $croot = &$level_1;

    $croot['children'][] = &$item1;
    $croot['children'][] = &$item2;

    $croot = &$root;

    print_r($croot);
}    

function this_fails()
{    
    $root = array('name'=>'root', 'children'=>array());
    $level_1 = array('name'=>'level_1', 'children'=>array());
    $item1 = array('name'=>'level_2_1', 'children'=>array());
    $item2 = array('name'=>'level_2_2', 'children'=>array());
    $croot = &$root;

    $stack = array();

    $croot['children'][] = &$level_1;
    $crootref = &$croot;

    array_push($stack, $crootref);

    $croot = &$level_1;

    $croot['children'][] = &$item1;
    $croot['children'][] = &$item2;

    # this works, assignment below - doesn't... WHY?
    #$x = array_pop($stack);
    #var_dump($x);

    $croot = array_pop($stack);

    print_r($croot);
}    

this_works();
echo "------------------\n";
this_fails();

?>

第一个函数提供预期的结果, 而第二个失败并声称递归循环:

Array
(
    [name] => root
    [children] => Array
        (
            [0] => Array
                (
                    [name] => level_1
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [name] => level_2_1
                                    [children] => Array
                                    (
                                    )

                                )

                            [1] => Array
                                (
                                    [name] => level_2_2
                                    [children] => Array
                                        (
                                        )

                                )

                           )

                )

        )

)
------------------
Array
(
    [name] => root
    [children] => Array
        (
            [0] => Array
                (
                    [name] => root
                    [children] => Array
 *RECURSION*
                )

    )

)

奇怪的是,如果在第二个函数中,中间 变量将用于从堆栈中获取值,结果再次正常。 我不明白发生了什么事。我如何获得根元素 由于一次同罪而多次成为自己的孩子?

最初,我需要从 XML 构建树(使用 sax 解析器) 并打算让“当前根”指向树节点 当前级别并将其推入/弹出堆栈并向其添加子元素, 但是,令人惊讶的是,由于出现的问题,我未能实施此计划 通过上面的两个函数。

那么,这种方法有什么问题呢?

【问题讨论】:

    标签: php arrays reference tree


    【解决方案1】:

    这是因为 PHP 在数组内部进行引用的奇怪方式。使用右侧引用进行普通(非引用)赋值通常不会将左侧变为引用,但数组内的引用在赋值中保留,即使没有引用运算符。

    我在下面评论了您的代码以帮助解释正在发生的事情,我希望我已经正确解释了这一点,现在是凌晨 1 点,我累了。

    $root = array('name'=>'root', 'children'=>array());
    $level_1 = array('name'=>'level_1', 'children'=>array());
    // $croot and $root now point to the same variable
    $croot = &$root;
    
    $stack = array();
    
    $croot['children'][] = &$level_1;
    // $crootref, $croot and $root all now point to the same variable
    $crootref = &$croot;
    // $stack[0], $crootref, $croot and $root all now point to the same variable.
    // $stack[0]['children'][0], $level_1, $croot['children'][0] point to the same variable
    array_push($stack, $crootref);
    // $croot, $level_1 and $stack[0]['children'][0] now point to the same variable
    // Infinite loop is caused as $stack[0]['children'][0] is now an alias for $croot
    // which contains $croot['children'][0] which is an alias for $stack[0]['children'][0]
    // which is an alias for $croot which contains....
    $croot = &$level_1;
    

    【讨论】:

      【解决方案2】:

      只是一种解决方法,使用 unset() 而不是 array_pop()。并且因为当您使用 array_pop() 时,输入数组的数组指针被重置,我使用 reset() 来模拟相同的结果,这里你去:

      <?php
      
      function this_fails_fixed()
      {    
          $root = array('name'=>'root', 'children'=>array());
          $level_1 = array('name'=>'level_1', 'children'=>array());
          $item1 = array('name'=>'level_2_1', 'children'=>array());
          $item2 = array('name'=>'level_2_2', 'children'=>array());
          $croot = &$root;
      
          $stack = array();
      
          $croot['children'][] = &$level_1;
          $crootref = &$croot;
      
          array_push($stack, $crootref);
      
          $croot = &$level_1;
      
          $croot['children'][] = &$item1;
          $croot['children'][] = &$item2;
      
          unset($croot[count($croot)-1]);
              reset($croot);
      
          print_r($croot);
      }    
      
      this_fails_fixed();
      
      ?>
      

      【讨论】:

        【解决方案3】:

        一张图片价值 1000 字。 花了一些时间才明白 到底发生了什么。

        我不得不使用 Xdebug 转储内部 数据正确并查看引用计数 以及复制对写入的影响。

        第一篇文章中的代码问题 这是作业吗

        $croot = array_pop($stack);

        当 croot 为 'level_1' 时,通过复制完成, 即 croot 的元素(与 level_1 相同) 填充有来自堆栈的数据和 此操作后croot与原来的root不一样了。

        图片会更好地解释。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-04
          • 2016-10-10
          相关资源
          最近更新 更多