【问题标题】:Recursive function inside class with foreach changes public value where it shouldn't带有foreach的类内的递归函数在不应该更改的地方更改了公共值
【发布时间】:2012-05-23 23:21:22
【问题描述】:

好吧,我真的很纠结这个。我希望你能帮助我。

我有我的班级,用来管理分层数据。输入是一个普通数组,结构如下(只是一个例子):

$list = array(
(object) array('id' => 1, 'nombre' => 'Cámaras de fotos', 'parentId' => null),
(object) array('id' => 2, 'nombre' => 'Lentes', 'parentId' => null),
(object) array('id' => 3, 'nombre' => 'Zoom', 'parentId' => 2),
(object) array('id' => 4, 'nombre' => 'SLR', 'parentId' => 1),
(object) array('id' => 5, 'nombre' => 'Primarios', 'parentId' => 2),
(object) array('id' => 6, 'nombre' => 'Sensor APS-C', 'parentId' => 4),
(object) array('id' => 7, 'nombre' => 'Full-frame', 'parentId' => 4),
(object) array('id' => 8, 'nombre' => 'Flashes', 'parentId' => null),
(object) array('id' => 9, 'nombre' => 'Compactas', 'parentId' => 1)
);

我以这种方式将数据输入到类中:

$Hierarchical = new Hierarchical;
$Hierarchical->plain = $list;

然后我有一个公共函数 (createTree) 来创建列表的多维数组表示。它完美地工作。它可以返回结果或将其存储在$this->tree 中。

如您所见,这非常简单。它调用私有函数iterateTree,即递归函数。

class Hierarchical {

    public $plain = array();
    public $tree = array();

    public function createTree($parentId=0, $return=false) {

    $tree = $this->iterateTree($parentId);

    if(!$return) {
        $this->tree = $tree;
    } else {
        return $tree;
    }

    }


    private function iterateTree($parentId) {

    $resArray = array();

    foreach($this->plain as $item) {

        if($item->parentId == $parentId) {

            $children = $this->iterateTree($item->id);

            if( count($children) > 0 ) {
                $item->children = $children;
            }

            $resArray[] = $item;

        }

    }

    return $resArray;

    } 

}

到目前为止一切顺利。它工作正常。

但是... 当我在调用createTree() 后想使用$this->plain 时出现问题。它不是返回原始数据集,而是返回原始输入之间的某种混合,并附加所有子数据(类似于$this->tree)。

我无法弄清楚为什么 $this->plain 的内容会被更改,在使用的两个函数中我都不会更改它的内容。

我尝试在foreach 之后取消设置foreach 中的变量,甚至将原始数组作为参数传递,并且在递归函数中根本不使用$this->plain。没有任何效果。

我也在类中使用任何其他可能改变其值的函数。

这完全是个谜!

【问题讨论】:

    标签: php class recursion foreach hierarchical


    【解决方案1】:

    在您的 foreach 循环中,$item 将是对数组中对象的引用,因此您正在更改该行中的同一对象

    $item->children = $children;
    

    这将影响原始数组$list$this->plain 中引用的对象。

    一种解决方案可能是在您的 foreach 循环中克隆 $item

    【讨论】:

    • 太棒了!非常感谢。
    【解决方案2】:

    根据Doug的回答,正确的函数是:(添加$itemAux = clone $item

    private function iterateTree($parentId) {
    
        $resArray = array();
    
        foreach($this->plain as $item) {
    
            $itemAux = clone $item;
    
            if($itemAux->parentId == $parentId) {
    
                $children = $this->iterateTree($itemAux->id);
    
                if( count($children) > 0 ) {
                    $itemAux->children = $children;
                }
    
                $resArray[] = $itemAux;
    
            }
    
        }
    
        return $resArray;
    
    } 
    

    【讨论】:

      【解决方案3】:

      补充道格的答案,尽管手册说“对象不是通过引用传递的”(http://www.php.net/manual/en/language.oop5.references。 php),将对象视为与可能“包含”它们的任何变量完全分离的实体可能会有所帮助,并且它们实际上是通过引用传递到任何地方...

      class testClass
      {
          public $var1 = 1;
      }
      
      function testFunc($obj)
      {
          $obj->var1 = 2;
      }
      
      
      $t = new testClass;
      testFunc($t);
      echo $t->var1; // 2
      

      所以当您执行$item->children = $children; 时,实际上您正在影响$plain 数组中的每个原始对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-25
        • 2010-09-20
        • 2019-08-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-01
        • 1970-01-01
        相关资源
        最近更新 更多