PHP 无限级缩进分类


PHP 无限极分类经常被使用应用,如菜单无限极分类,国家省市级分类,商城等等

核心类

比如在TP6中使用  代码路径

项目文件夹/extend 新建 holyrisk文件夹 Tree.php

<?php


namespace holyrisk;


class Tree
{
    /**
     * @description 无限极分类实现 - 嵌套形式
     * @author Holyrisk
     * @date 2021/4/22 22:41
     * @param        $list  需要被处理的数组
     * @param string $pk id
     * @param string $pid 父级id
     * @param string $child 子级名称
     * @param int    $root 顶级分类的值
     * @return array
     */
    public  function buildTree($list, $pk='id', $pid='pid', $child='children', $root=0){
        if (empty($list)){
            return [];
        }
        $tree = array();
        $packData = array();
        foreach ($list as $data) {
            $packData[$data[$pk]] = $data;
        }
        foreach ($packData as $key=>$val){
            if($val[$pid] == $root){
                $tree[] = &$packData[$key];
            }else{
                $packData[$val[$pid]][$child][] = &$packData[$key];
            }
        }

        return $tree;
    }

    /**
     * 无限极分类实现 - 列表形式 取得等级 级别
     * @param $array 分类数据
     * @param $pid 父ID
     * @param $level 分类级别
     * @return array 分好类的数组 直接遍历即可 $level可以用来遍历缩进
     */
    public function getTreeLevel($array, $pid =0, $level = 0){

        //声明静态数组,避免递归调用时,多次声明导致数组覆盖
        static $list = [];
        foreach ($array as $key => $value){
            //第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点
            if ($value['pid'] == $pid){
                //父节点为根节点的节点,级别为0,也就是第一级
                $value['level'] = $level;
                //把数组放到list中
                $list[] = $value;
                //把这个节点从数组中移除,减少后续递归消耗
                unset($array[$key]);
                //开始递归,查找父ID为该节点ID的节点,级别则为原级别+1
                $this->getTreeLevel($array, $value['id'], $level+1);

            }
        }
        return $list;
    }

    /**
     * 缩进形式 无限级 分类
     * 参考 https://www.cnblogs.com/phpk/p/10929918.html
     * @param $array
     * @param int $pid
     * @param int $level
     * @return array
     */
    public function getTreeHtmlSelect($array, $pid =0, $level = 0)
    {
        $list = $this->getTreeLevel($array,$pid,$level);
        foreach ($list as $key => $value){
            $list[$key]['name'] = str_repeat('>>', $value['level']). $value['name'];
        }
        return $list;
    }

}

代码调用演示

use holyrisk\Tree;


$array = array(
    array('id' => 1, 'pid' => 0, 'name' => '河北省'),
    array('id' => 2, 'pid' => 0, 'name' => '北京市'),
    array('id' => 3, 'pid' => 1, 'name' => '邯郸市'),
    array('id' => 4, 'pid' => 2, 'name' => '朝阳区'),
    array('id' => 5, 'pid' => 2, 'name' => '通州区'),
    array('id' => 6, 'pid' => 4, 'name' => '望京'),
    array('id' => 7, 'pid' => 4, 'name' => '酒仙桥'),
    array('id' => 8, 'pid' => 3, 'name' => '永年区'),
    array('id' => 9, 'pid' => 1, 'name' => '武安市'),
);

$son =  (new Tree())->buildTree($array);
$list =  (new Tree())->getTreeLevel($array);
$arr = (new Tree())->getTreeHtmlSelect($array);
echo "<pre>";
echo "原始数据"."<br />";
echo print_r($array);
echo "嵌套形式"."<br />";
echo print_r($son);
echo "列表级别形式"."<br />";
echo print_r($list);
echo "列表缩进 - 给HTML下拉框使用形式"."<br />";
echo print_r($arr);
echo "</pre>";

输出打印

原始数据
Array
(
    [0] => Array
        (
            [id] => 1
            [pid] => 0
            [name] => 河北省
        )

    [1] => Array
        (
            [id] => 2
            [pid] => 0
            [name] => 北京市
        )

    [2] => Array
        (
            [id] => 3
            [pid] => 1
            [name] => 邯郸市
        )

    [3] => Array
        (
            [id] => 4
            [pid] => 2
            [name] => 朝阳区
        )

    [4] => Array
        (
            [id] => 5
            [pid] => 2
            [name] => 通州区
        )

    [5] => Array
        (
            [id] => 6
            [pid] => 4
            [name] => 望京
        )

    [6] => Array
        (
            [id] => 7
            [pid] => 4
            [name] => 酒仙桥
        )

    [7] => Array
        (
            [id] => 8
            [pid] => 3
            [name] => 永年区
        )

    [8] => Array
        (
            [id] => 9
            [pid] => 1
            [name] => 武安市
        )

)
1嵌套形式
Array
(
    [0] => Array
        (
            [id] => 1
            [pid] => 0
            [name] => 河北省
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [pid] => 1
                            [name] => 邯郸市
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 8
                                            [pid] => 3
                                            [name] => 永年区
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [id] => 9
                            [pid] => 1
                            [name] => 武安市
                        )

                )

        )

    [1] => Array
        (
            [id] => 2
            [pid] => 0
            [name] => 北京市
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 4
                            [pid] => 2
                            [name] => 朝阳区
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 6
                                            [pid] => 4
                                            [name] => 望京
                                        )

                                    [1] => Array
                                        (
                                            [id] => 7
                                            [pid] => 4
                                            [name] => 酒仙桥
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [id] => 5
                            [pid] => 2
                            [name] => 通州区
                        )

                )

        )

)
1列表级别形式
Array
(
    [0] => Array
        (
            [id] => 1
            [pid] => 0
            [name] => 河北省
            [level] => 0
        )

    [1] => Array
        (
            [id] => 3
            [pid] => 1
            [name] => 邯郸市
            [level] => 1
        )

    [2] => Array
        (
            [id] => 8
            [pid] => 3
            [name] => 永年区
            [level] => 2
        )

    [3] => Array
        (
            [id] => 9
            [pid] => 1
            [name] => 武安市
            [level] => 1
        )

    [4] => Array
        (
            [id] => 2
            [pid] => 0
            [name] => 北京市
            [level] => 0
        )

    [5] => Array
        (
            [id] => 4
            [pid] => 2
            [name] => 朝阳区
            [level] => 1
        )

    [6] => Array
        (
            [id] => 6
            [pid] => 4
            [name] => 望京
            [level] => 2
        )

    [7] => Array
        (
            [id] => 7
            [pid] => 4
            [name] => 酒仙桥
            [level] => 2
        )

    [8] => Array
        (
            [id] => 5
            [pid] => 2
            [name] => 通州区
            [level] => 1
        )

)
1列表缩进 - 给HTML下拉框使用形式
Array
(
    [0] => Array
        (
            [id] => 1
            [pid] => 0
            [name] => 河北省
            [level] => 0
        )

    [1] => Array
        (
            [id] => 3
            [pid] => 1
            [name] => >>邯郸市
            [level] => 1
        )

    [2] => Array
        (
            [id] => 8
            [pid] => 3
            [name] => >>>>永年区
            [level] => 2
        )

    [3] => Array
        (
            [id] => 9
            [pid] => 1
            [name] => >>武安市
            [level] => 1
        )

    [4] => Array
        (
            [id] => 2
            [pid] => 0
            [name] => 北京市
            [level] => 0
        )

    [5] => Array
        (
            [id] => 4
            [pid] => 2
            [name] => >>朝阳区
            [level] => 1
        )

    [6] => Array
        (
            [id] => 6
            [pid] => 4
            [name] => >>>>望京
            [level] => 2
        )

    [7] => Array
        (
            [id] => 7
            [pid] => 4
            [name] => >>>>酒仙桥
            [level] => 2
        )

    [8] => Array
        (
            [id] => 5
            [pid] => 2
            [name] => >>通州区
            [level] => 1
        )

    [9] => Array
        (
            [id] => 1
            [pid] => 0
            [name] => 河北省
            [level] => 0
        )

    [10] => Array
        (
            [id] => 3
            [pid] => 1
            [name] => >>邯郸市
            [level] => 1
        )

    [11] => Array
        (
            [id] => 8
            [pid] => 3
            [name] => >>>>永年区
            [level] => 2
        )

    [12] => Array
        (
            [id] => 9
            [pid] => 1
            [name] => >>武安市
            [level] => 1
        )

    [13] => Array
        (
            [id] => 2
            [pid] => 0
            [name] => 北京市
            [level] => 0
        )

    [14] => Array
        (
            [id] => 4
            [pid] => 2
            [name] => >>朝阳区
            [level] => 1
        )

    [15] => Array
        (
            [id] => 6
            [pid] => 4
            [name] => >>>>望京
            [level] => 2
        )

    [16] => Array
        (
            [id] => 7
            [pid] => 4
            [name] => >>>>酒仙桥
            [level] => 2
        )

    [17] => Array
        (
            [id] => 5
            [pid] => 2
            [name] => >>通州区
            [level] => 1
        )

)