简体   繁体   English

如何在PHP中将此MPTT数组转换为树结构?

[英]How to convert this MPTT array into a tree structure in PHP?

I've got hierarchal data in the database, stored in Modified Preorder Tree Traversal format. 我在数据库中有分层数据,以Modified Preorder Tree Traversal格式存储。 I'm pulling the data in a query that looks something like "SELECT ID, Left , Right , Name, etc FROM Table ORDER BY Left ;". 我在一个看起来类似“SELECT ID, LeftRight ,Name等FROM FROM ORDER BY Left ;”的查询中提取数据。 I'm trying to convert this data from a flat array the DB gives me into a tree-structure which I will then output as JSON with PHP's json_encode function. 我试图将这个数据从一个平面数组转换成DB给我一个树结构,然后我将用PHP的json_encode函数输出为JSON。

I'm having trouble getting my tree structure code to work beyond the first level, though. 但是,我无法让我的树形结构代码超出第一级。 Here's a minimum test case: 这是一个最小的测试用例:

<pre><?php

function projectListToTree($projects) {
    $stack = Array();
    for($x =0; $x < count($projects); $x++) {
        $project = $projects[$x];
        $project['Children'] = Array();

        while(count($stack) > 0 && $stack[count($stack) - 1]['Right'] < $project['Right']) {
            array_pop($stack);
        }

        if(count($stack) > 0) {
            $stack[count($stack) - 1]['Children'][] = $project; 
            echo "Adding " . $project['Name'] . " to " . $stack[count($stack) - 1]['Name'] . " for a total of "
                . count($stack[count($stack) - 1]['Children']) . " kids\n";
        } else {
            echo "No parent\n"; 
        }

        echo "stack count: " . count($stack) . "\n";

        array_push($stack, $project);
    }

    echo "Left in stack: " . count($stack) . "\n";

    return $stack[0];
}

/*
This is basically what comes from the DB.
Should be:
  Parent
    First Child
    Second Child
      Grand Child
*/
$projects = Array(
    Array(
        "ID" => "2",
        "Left" => "2",
        "Right" => "9",
        "ParentID" => "1",
        "Name" => "Parent"
    ),
    Array(
        "ID" => "3",
        "Left" => "3",
        "Right" => "4",
        "ParentID" => "2",
        "Name" => "First Child"
    ),
    Array(
        "ID" => "4",
        "Left" => "5",
        "Right" => "8",
        "ParentID" => "2",
        "Name" => "Second Child"
    ),
    Array(
        "ID" => "5",
        "Left" => "6",
        "Right" => "7",
        "ParentID" => "4",
        "Name" => "Grand Child"
    )
);


$tree = projectListToTree($projects);
echo "-----\n\n\n\n";
var_dump($tree);

?></pre>

And here's what I'm getting for output: 这就是我得到的输出:

No parent
stack count: 0
Adding First Child to Parent for a total of 1 kids
stack count: 1
Adding Second Child to Parent for a total of 2 kids
stack count: 1
Adding Grand Child to Second Child for a total of 1 kids
stack count: 2
Left in stack: 3
-----



array(6) {
  ["ID"]=>
  string(1) "2"
  ["Left"]=>
  string(1) "2"
  ["Right"]=>
  string(1) "9"
  ["ParentID"]=>
  string(1) "1"
  ["Name"]=>
  string(6) "Parent"
  ["Children"]=>
  array(2) {
    [0]=>
    array(6) {
      ["ID"]=>
      string(1) "3"
      ["Left"]=>
      string(1) "3"
      ["Right"]=>
      string(1) "4"
      ["ParentID"]=>
      string(1) "2"
      ["Name"]=>
      string(11) "First Child"
      ["Children"]=>
      array(0) {
      }
    }
    [1]=>
    array(6) {
      ["ID"]=>
      string(1) "4"
      ["Left"]=>
      string(1) "5"
      ["Right"]=>
      string(1) "8"
      ["ParentID"]=>
      string(1) "2"
      ["Name"]=>
      string(12) "Second Child"
      ["Children"]=>
      array(0) {
      }
    }
  }
}

As you can see, somewhere "Grandchild" is getting lost, even though the output in the projectListToTree function seems to indicate it should be there. 正如你所看到的,即使projectListToTree函数中的输出似乎表明它应该存在,某个地方“孙子”也会迷路。 It seems like any tree structure I throw at it drops anything below the second level. 看起来我抛出的任何树形结构都会降低第二级以下的任何结构。 Any insight into what might be happening? 对可能发生的事情的任何见解?

Thanks! 谢谢!

The problem is that assigning an array does not copy references, but makes a copy of the array. 问题是分配数组不会复制引用,而是复制数组。 This means, that the "Second Child" array you have in "children" of the "Parent" node is not the same array that you add "Grandchild" to, but a copy of it. 这意味着,您在“父”节点的“子”中拥有的“第二个子”数组与您添加“孙子”的数组不同,而是它的副本。

To resolve the issue, you have to explicitly use reference assignment instead of copying: 要解决此问题,您必须显式使用引用分配而不是复制:

function projectListToTree($projects) {
    $stack = Array();
    for($x =0; $x < count($projects); $x++) {
        $project = &$projects[$x];
        $project['Children'] = array();

        while(count($stack) > 0 && $stack[count($stack) - 1]['Right'] < $project['Right']) {
                array_pop($stack);
        }

        if(count($stack) > 0) {
                $stack[count($stack) - 1]['Children'][] = &$project; 

                echo "Adding " . $project['Name'] . " to " . $stack[count($stack) - 1]['Name'] . " for a total of "
                        . count($stack[count($stack) - 1]['Children']) . " kids\n";

                echo "\n";
        } else {
                echo "No parent\n"; 
        }

        echo "stack count: " . count($stack) . "\n";

        $stack[] = &$project;
    }

    echo "Left in stack: " . count($stack) . "\n";

    return $stack[0];
}

Note, that an ampersand was added at three places. 请注意,在三个地方添加了&符号。

Because of this issue, one has to be extremely careful when using nested arrays and assignment operators in php. 由于这个问题,在php中使用嵌套数组和赋值运算符时必须非常小心。

This also means that processor usage and memory footprint is intensive when using lots of data in nested arrays. 这也意味着在嵌套数组中使用大量数据时,处理器使用率和内存占用量很大。 For example, in the above example, when projectListToTree() returns, the complete array tree is copied to the local variable $tree and (since the php garbage collector sucks) is in memory twice. 例如,在上面的例子中,当projectListToTree()返回时,完整的数组树被复制到局部变量$ tree并且(因为php垃圾收集器很糟糕)在内存中两次。

Have you put an echo statement in to see when you're calling array_pop()? 你有一个echo语句,看看你何时调用array_pop()? From reading this without testing, I think you're popping the record off the stack and throwing it away. 通过阅读本文而不进行测试,我认为你正在从堆栈中弹出记录并扔掉它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM