PHP多种方式实现无限级分类

作者: 温新

分类: 【PHP基础】

阅读: 4164

时间: 2020-03-26 02:45:03

关于无限级分类,这是一个经常用到的知识点,做web开发,绝大多数的情况会使用到它。使用不同的方式实现就会有不一样的性能开销。对于国民级的递归实现方式,这是最简单也是最消耗性能的方式,而使用引用的方式来实现,开销则会小很多。

那么如何去选择?对于分类不多的项目,递归与引用的实现,性能开销相差无几;对于分类很多的项目,推荐使用引用的方式实现。

方式一 array_merge合并数组方式实现

/**
 * 方式一 array_merge合并数组方式实现
 *
 * @param array   $data     二维数组,需要递归的数组数据
 * @param integer $pid      父ID,默认顶级分类
 * @param integer $level    层次
 * 
 * @return array  $arrTree  返回值,排序好的二维数组
 */
function makeTreeOne($data , $pid = 0 , $level = 0){
    $arrTree = [];
    foreach($data as $k => $v){
        // 判断是否为上级分类
        if($v['parentId'] == $pid){
            $v['level'] = $level;
            $arrTree[]  = $v;
            // 此处是重点
            // 递归调用查找下级分类,查找时会有返回值,将该返回值赋值给一个新变量
            $res = makeTreeOne($data , $v['areaId'] , $level + 1);
            // 删除遍历过的数据索引,减少性能开销
            unset($data[$k]);
            // 合并数组
            $arrTree = array_merge($arrTree , $res);
        }
    }
    return $arrTree;
}

方式二 静态变量方式实现

/**
 * 方式二 静态变量方式实现
 *
 * @param array   $data     二维数组,需要递归的数组数据
 * @param integer $pid      父ID,默认顶级分类
 * @param integer $level    层次
 * 
 * @return array  $arrTree  返回值,排序好的二维数组
 */
function makeTreeTwo($data , $pid = 0 , $level = 0){
    // 此处是重点
    static $arrTree = [];

    foreach($data as $k => $v){
        if($v['parentId'] == $pid){
            $v['level'] = $level;
            // 使用静态,只会初始化一次,当遍历下一个分类时,保留上一次数据
            $arrTree[]  = $v;
            unset($k);
            makeTreeTwo($data , $v['areaId'] , $level + 1);
        }
    }
    return $arrTree;
}

方式三 全局变量方式实现

/**
 * 方式三 全局变量方式实现
 *
 * @param array   $data     二维数组,需要递归的数组数据
 * @param integer $pid      父ID,默认顶级分类
 * @param integer $level    层次
 * 
 * @return array  $arrTree  返回值,排序好的二维数组
 */
$tree = [];
function makeTreeThree($data , $pid = 0 , $level = 0){
    global $tree;

    foreach($data as $k => $v){
        if($v['parentId'] == $pid){
            $v['level'] = $level;
            $tree[]  = $v;
            makeTreeThree($data , $v['areaId'] , $level + 1);
        }
    }
    return $tree;
}

方式四 引用方式实现(一)

/**
 * 方式四 引用方式实现(一)
 *
 * @param array   $data     二维数组,需要递归的数组数据
 * @param integer $pid      父ID,默认顶级分类
 * @param integer $level    层次
 * 
 * @return array  $arrTree  返回值,排序好的二维数组
 */
function makeTreeFour($data , $pid = 0 , $level = 0 , &$tree = []){
    foreach($data as $v){
        if($v['parentId'] == $pid){
            $v['level'] = $level;
            $tree[] = $v;
            makeTreeFour($data , $v['areaId'] , $level + 1 , $tree);
        }
    }
    return $tree;
}

方式五 引用方式实现(二)【推荐使用】

/**
 * 方式五 引用方式实现(二)
 *
 * @param array   $data     二维数组,需要递归的数组数据
 * @param integer $pid      父ID,默认顶级分类
 * @param integer $level    层次
 * 
 * @return array  $arrTree  返回值,多维数组
 */
function makeTreeFive($data , $pid = 0 , $level = 0){
    // 存储构造好的数组数据
    $indexArray = [];
    foreach($data as $k => $v){
        $indexArray[$v['areaId']] = $v;
    }

    // 存储递归整理的数组数据
    $tree = [];
    foreach($indexArray as $k => $v){
        // 判断是否为上级分类
        if($v['parentId'] == $pid){
            // 顶级分类则将地址存放到数组tree中
            $tree[] = &$indexArray[$k];
        }else{
            // 不是顶级分类,则将地址存放到父级分类的son节点中
            $indexArray[$v['parentId']]['son'][] = &$indexArray[$k];
        }
    }    
    return $tree;
}

2021-10-14日更新

测试数据为15034条,所用字段为 id、pid、name。

电脑配置:Intel(R) Core(TM) i7-10700 CPU、32G内存、64位系统。

测试结果:推荐使用 方式五。

测试结果对比

测试的结果不太稳定,但是差距不太大。

方式一:所花费时间 11.3940298557秒;

方式二:所花费时间 11.1888649464秒;

方式三:所花费时间 11.2277669907秒,结果输出到浏览器时页面出现崩溃;

方式四:所花费时间 11.2678568363秒,结果输出到浏览器时页面出现崩溃;

方式五:所花费时间 0.0672979355秒。

由此可见,使用方式五的引用方式所花费的时间是最少的,因此,请开始使用它吧。

我是温新,期待和优秀的你一起同行!

夕阳何处寻

2020年03月26日

请登录后再评论