在PHP数组中循环生成层次结构

4

我已经花了几个小时来解决这个问题。为了加速我的网页,我只请求一次数据库以获取所有类别,然后想使用PHP对数组进行排序。

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => name1
            [parent] => 0
            [children] => 
        )
   [1] => Array
    (
        [id] => 2
        [name] => name2
        [parent] => 1
        [children] => 
    )
)

我需要得到类似这样的东西


Array
(
    [0] => Array
        (
            [id] => 1
            [name] => name1
            [parent] => 0
            [children] => Array
                  (
                      [id] => 2
                      [name] => name2
                      [parent] => 1
                      [children] => 
                  )
        )

)

问题在于要制作适用于任何层次的结构,以便可以循环使用。请帮忙!

5个回答

4
有许多解决方案可以减少这里的开销。但是,如果不知道您的约束条件,很难推荐一种方法。
例如:
1.使用邻接模型-请参阅dnagirl答案中我的评论 2.将所有数据加载到PHP中,然后使用递归算法创建嵌套树(这将非常慢,并且会受益于一些缓存) 3.编写一个递归存储过程,它按深度优先树遍历排序返回结果集
将第二个示例更接近代码...类似于...
 function build_tree(&$unsorted, $start_node)
 {
     $out=array();
     foreach($unsorted as $key=>$node) {
        if ($node['parent']==$start_node) {
            $node['children']=build_tree($unsorted, $key);
            unset($unsorted[$key]);
            $out[]=$node;
        }
     }
     return $out;
 } 
 $threaded_tree=build_tree($list_of_nodes, 0); // assumes that the root is the first element

你是不是想用嵌套集模型而不是邻接表? - Wiseguy

0
foreach ($dataFromMySQL as $e) {
    $all[$e['id']] = $e;
    $ref = &$all[$e['id'];
    if ($e['parent']) $all[$e['id']]['children'][] = $ref;
    else $hierarchy[$e['id']] = $ref;
}

这要求父级元素在其子元素之前始终被填充


我应该拥有什么样的数据库结构才能最好地适应它? - user597214
我以为你已经有了数据库结构... 你得到的结构很好。根据你存储/显示的信息,@dnagirl可能是正确的... Ajax可能更好。如果你需要一次性获取所有信息,请使用你提出的数据库结构与我上面编写的填充方法。 - Mikhail

0

不确定您是否已经找到答案,但我今天也在寻找同样的解决方案,最终我自己创建了一个解决方案。下面的代码是我刚刚创建的类,它适用于 PHP 数组和对象,并且可以递归到无限数量的维度。

GitHub https://github.com/DukeOfMarshall/PHP-Array-Heirarchy-Display

使用此代码的简单示例:

<?php

require_once('Arrays.class.php');
$display = new Array_Functions();

$display->display_hierarchy($multidimensional_array);

?>

还有其他选项可以设置,但那只是一个数组或对象的直接层次显示。

<?php

class Array_Functions {
public $number_of_tabs  = 3; # The default number of tabs to use when branching out
private $counter            = 0; # The counter to use for the number of tab iterations to use on the current branch

public $display_square_brackets     = TRUE; 
public $display_squiggly_brackets = FALSE;
public $display_parenthesis           = FALSE;

public $display_apostrophe  = TRUE;
public $display_quotes        = FALSE;

public function __construct(){
}

/**
 * Displays the array in an organized heirarchy and even does so recursively
 * 
 * $array ARRAY - The array to display in a heirarchy
 * 
 * $key_bookends STRING - The character to place on either side of the array key when printed
 * @@ square - Displays a set of square brackets around the key (DEFAULT)
 * @@ squiggly - Displays a set of squiggly brackets around the key
 * @@ parenthesis - Displays a set of parenthesis around the key
 * @@ FALSE - Turns off the display of bookends around the array key
 * 
 * $key_padding STRING - The padding to use around the array key with printed
 * @@ quotes - Pads the array key with double quotes when printed
 * @@ apostrophe - Pads the array key with apostrophes when printed (DEFAULT)
 * @@ FALSE - Turns off the display of padding around the array key
 * 
 * $number_of_tabs_to_use INT - The number of tabs to use when a sub array within the array creates a branch in the heirarchy
 * 
 */
public function display_hierarchy($array, $key_bookends = '', $key_padding = '', $number_of_tabs_to_use = ''){
    # Convert the input to a JSON and then back to an array just to make sure we know what we're working with
    $array = $this->convert_object_to_array($array);

    # If the $array variable is still not an array, then error out.
    # We're not going to fool around with your stupidity
    if(gettype($array) != 'array'){
        echo 'Value submitted was '.strtoupper(gettype($array)).' instead of ARRAY or OBJECT. Only arrays or OBJECTS are allowed Terminating execution.';
        exit();
    }

    # Establish the bookend variables
    if($key_bookends != '' || !$key_bookends){
        if(strtolower($key_bookends) == 'square'){
            $this->display_square_brackets      = TRUE;
            $this->display_squiggly_brackets    = FALSE;
            $this->display_parenthesis            = FALSE;
        }elseif(strtolower($key_bookends) == 'squiggly'){
            $this->display_square_brackets      = TRUE;
            $this->display_squiggly_brackets    = TRUE;
            $this->display_parenthesis            = FALSE;
        }elseif(strtolower($key_bookends) == 'parenthesis'){
            $this->display_square_brackets      = FALSE;
            $this->display_squiggly_brackets    = FALSE;
            $this->display_parenthesis          = TRUE;
        }elseif(!$key_bookends){
            $this->display_square_brackets      = FALSE;
            $this->display_squiggly_brackets    = FALSE;
            $this->display_parenthesis            = FALSE;
        }
    }


    # Establish the padding variables
    if($key_padding != '' || !$key_padding){
        if(strtolower($key_padding) == 'apostrophe'){
            $this->display_apostrophe = TRUE;
            $this->display_quotes       = FALSE;
        }elseif(strtolower($key_padding) == 'quotes'){
            $this->display_apostrophe = FALSE;
            $this->display_quotes       = TRUE;
        }elseif(!$key_padding){
            $this->display_apostrophe = FALSE;
            $this->display_quotes       = FALSE;
        }
    }       

    # Establish variable for the number of tabs
    if(isset($number_of_tabs_to_use) && $number_of_tabs_to_use != ''){
        $this->number_of_tabs = $number_of_tabs_to_use;
    }

    foreach($array as $key => $value){
        $this->insert_tabs();

        if(is_array($value)){
            echo $this->display_padding($key)." => {<BR>";

            $this->counter++;
            $this->display_hierarchy($value);
            $this->counter--;
            $this->insert_tabs();
            echo '} <BR>';
        }else{
            echo $this->display_padding($key)." => ".$value.'<BR>';
        }
    }
}

# Inserts tab spaces for sub arrays when a sub array triggers a branch in the heirarchy
# Helps to make the display more human readable and easier to understand
private function insert_tabs(){
    for($i=1; $i<=$this->counter; $i++){
        for($x=1; $x<=$this->number_of_tabs; $x++){
            echo '&emsp;';
        }
    }
}

# Takes a PHP object and converts it to an array
# Works with single dimension and multidimensional arrays
public function convert_object_to_array($object){
    $object = json_decode(json_encode($object), TRUE);
    return $object;
}

# Sets the displayed padding around the array keys when printed on the screen
public function display_padding($value){
    $default_container = "['VALUE_TO_REPLACE']";

    $value = str_replace("VALUE_TO_REPLACE", $value, $default_container);

    if($this->display_square_brackets){
    }elseif($this->display_squiggly_brackets){
        $value = str_replace('[', '{', $value);
        $value = str_replace(']', '}', $value);
    }elseif($this->display_parenthesis){
        $value = str_replace('[', '(', $value);
        $value = str_replace(']', ')', $value);
    }else{
        $value = str_replace('[', '', $value);
        $value = str_replace(']', '', $value);
    }

    if($this->display_apostrophe){
    }elseif($this->display_quotes){
        $value = str_replace("'", '"', $value);
    }else{
        $value = str_replace("'", '', $value);
    }

    return $value;
}
}

?>

0

你正在使用邻接模型来构建你的层次结构。你要么需要多次查询数据库,要么如果层级数量已知,可以构建一个带有每个层级子句的联合查询。

如果允许的话,你可能会发现当父级被点击时调用子级的 AJAX 解决方案更容易编程且更有效率。


那么,在数据库中存储层次结构的最佳方法是什么,以避免出现这样的问题呢? - user597214
实际上这是父级引用,而不是邻接 - 请参阅http://articles.sitepoint.com/article/hierarchical-data-database以获取邻接模型的描述。 - symcbean
@user597214:学习如何在SQL中建模层级结构的绝佳参考资料是Joe Celko的《SQL for Smarties中的树和层次结构》。使用最适当的模型取决于许多因素,其中最重要的因素之一是树中数据更改的频率。 - dnagirl
1
@symcbean 有什么区别? - Wiseguy

0
你所需要的是递归,但对我来说如何处理 PHP 中的递归并不是很清楚,而且文档中几乎没有关于这个主题的内容。
你可能会对查看 thisthis 文章感兴趣。

1
在PHP中,递归与大多数其他类似语言中的递归相同。从函数本身调用该函数,并确保在函数中有停止条件。 - dnagirl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接