美文网首页web后端php
php 递归无限分类

php 递归无限分类

作者: 云龙789 | 来源:发表于2017-02-10 09:37 被阅读701次

    参考
    因为递归的效率相对来说比较低,所以很少使用,尤其是在查询数据库的时候对数据库的长时间占用很不合理。

    但是递归遍历无限分类列表还是相当重要的,而且还可以对数据进行格式化处理,如果嫌弃效率问题,本人给你一个好建议就是缓存。比如当用户登录的时候判断完用户的权限后获取用户可以操作的菜单,然后递归格式化菜单分类列表,然后缓存起来,这样用户之后的操作都不会涉及到递归获取菜单,效率可以大大提升。

    个人理解 。其实递归分类的本质是
    1.把一个表里面的所有数据都取出来
    2-1.如果$fid == $val['fid']
    2-2.把数据遍历后,重新组合。把名字根据分类级别,添加n倍“---”
    2-3.添加完之后,还有递归调用本函数

    以下是在laravel中使用递归遍历菜单的方法:

    • 1.在项目的Common目录中的function.php中添加以下函数:
    /**
     *
     * @param array $data 结果集 (整个表的结果)
     * @param int $fid 父类ID
     * @param array $result 结果数据
     * @param int $deep 分类级数
     * @return array
     */
    function getList($data, $fid = 0, &$result = array(), $deep = 0)
    {
        $deep += 1;
        foreach($data as $key => $val)   //遍历之后,此处的$key是键(其实是数组的序列号),$val是一条数据结果
        {
        $val = $this->objectToArray($val);   //注意,此处$val是对象,需要转换成数组
            if($fid == $val['fid'])
            {
                $result[$key]['id'] = $val['id'];
                $result[$key]['name'] = "|".str_repeat("--", $deep).$val['name'];
                $result[$key]['fid'] = $val['fid'];
                $this->getList($data, $val['id'], $result, $deep);
            }
        }
        return $result;
    }
    
    • 2.在需要的地方直接getList($data)就可以,比如在Controller中:
    public function test()
        {
            $data = \DB::table('test')->get();
    
             $newClass = $this->getList($data);
            return view('welcome',compact('newClass'));
    
        }
    
    数据表 dd($data)结果 dd($newClass,查看getList()函数的执行顺序) echo $key."\n"结果 print_r($val)."\n";结果 $newClass = $this->getList($data); dd($newClass); 报错 dd($newClass);结果 getList()函数中,如果$result不加传指符$,dd($newClass)结果)
    • 3.前台直接遍历输出就可以了。
    <select name="class">
       @foreach($newClass as  $v)
            <option value="{{ $v['id'] }}">{{$v['name']}}</option>
       @endforeach
    </select>
    
    效果图
    • 数据结构
    DROP TABLE IF EXISTS `class`;
    CREATE TABLE `class` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `fid` int(10) unsigned NOT NULL DEFAULT '0',
      `name` varchar(50) NOT NULL,
      `status` tinyint(3) unsigned NOT NULL DEFAULT '1',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    补充

        public function test()
    {
        $data = \DB::table('test')->get();
    
         $newClass = $this->getList($data);
            dd($newClass);
    
    }
    这个执行会报错,原因是遍历$data后的$val值是对象。所以我们需要一个对象转数组的执行
    

    写的有点乱,主要是为了展示效果图。下面把源码重新整理下

    // TestController.php里代码
    class TestController extends Controller
    {
    
        public function test()
        {
            $data = \DB::table('test')->get();
    
             $newClass = $this->getList($data);
            return view('welcome',compact('newClass'));
    
        }
        /**
         *
         * @param array $data 结果集 (整个表的结果)
         * @param int $fid 父类ID
         * @param array $result 结果数据
         * @param int $deep 分类级数
         * @return array
         */
        public function getList($data, $fid = 0, &$result = array(), $deep = 0)
        {
            $deep += 1;
            foreach($data as $key => $val)
            {
                $val = $this->objectToArray($val);
                if($fid == $val['fid'])
                {
                    $result[$key]['id'] = $val['id'];
                    $result[$key]['name'] = "|".str_repeat("--", $deep).$val['name'];
                    $result[$key]['fid'] = $val['fid'];
                    $this->getList($data, $val['id'], $result, $deep);
                }
            }
            return $result;
        }
        /*
         * 数组转对象
         */
        public function objectToArray($e)
        {
            $e = (array)$e;
            foreach ($e as $k => $v) {
                if (gettype($v) == 'resource') return;
                if (gettype($v) == 'object' || gettype($v) == 'array')
                    $e[$k] = (array)$this->objectToArray($v);
            }
            return $e;
        }
    }
    
    
    //welcome.php
    <select name="class">
       @foreach($newClass as  $v)
            <option value="{{ $v['id'] }}">{{$v['name']}}</option>
       @endforeach
    </select>
    

    还有一种方法:不使用传指符,而是把接收的$result数组定义成静态方法。静态方法能够保存原来的数据,但是如果不使用静态方法,$result=array();相当于每次都把$result定义成数组,并赋值为空

    
    
       public function getList($data, $fid = 0,  $deep = 0)
        {
            static $result=array();
            $deep += 1;
            foreach($data as $key => $val)
            {
                $val = $this->objectToArray($val);
                if($fid == $val['fid'])
                {
                    $result[$key]['id'] = $val['id'];
                    $result[$key]['name']= "|".str_repeat("--", $deep).$val['name'];
                    $result[$key]['fid'] = $val['fid'];
                    $this->getList($data, $val['id'],  $deep);
                }
            }
            return $result;
        }
    

    思考

    那么,为什么我们一定要与定义$result=[]呢,这是因为我们的函数里面,不仅有if,还有else。
    也就是说当if不存在时,我们执行的代码就是
    foreach($data as $key => $val)
            {
                $val = $this->objectToArray($val);
               
            }
            return $result;
    
    这个时候,我们根本没有给$result定义,也没有给它赋值,当然就会报错
    如果想要解决这个问题,我们只能做个测试,来一个else,然后给$result赋值
    
    但是这样还是不能拼接我们获取的值,我只是说我们解决这种情况的处理。
    但是放倒全局来说,所以我们还是用static或者传指符吧
    

    $contry = [
        ['id'=>1,'fid'=>0,'name'=>'国内'],
        ['id'=>2,'fid'=>1,'name'=>'河南'],
        ['id'=>3,'fid'=>2,'name'=>'郑州'],
        ['id'=>4,'fid'=>1,'name'=>'广东'],
        ['id'=>5,'fid'=>4,'name'=>'深圳'],
    ];
    
    function getList($data, $fid = 0, &$result = array(), $deep = 0)
    {
        $deep += 1;
        foreach($data as $key => $val)   //遍历之后,此处的$key是键(其实是数组的序列号),$val是一条数据结果
        {
            if($fid == $val['fid'])
            {
                $result[$key]['id'] = $val['id'];
                $result[$key]['name'] = "|".str_repeat("--", $deep).$val['name'];
                $result[$key]['fid'] = $val['fid'];
                getList($data, $val['id'], $result, $deep);
            }
        }
        return $result;
    }
    $res = getList($contry);
    echo json_encode($res);
    

    相关文章

      网友评论

      • 82709210c359:楼主写得不错,学习了
        PS:
        生成测试数据
        INSERT INTO `categories` (`id`, `pid`, `name`, `depth`, `created_at`, `updated_at`)
        VALUES
        (1, 0, '国内新闻', NULL, NULL, NULL),
        (2, 0, '国际新闻', NULL, NULL, NULL),
        (3, 2, '美国新闻', NULL, NULL, NULL),
        (4, 2, '德国新闻', NULL, NULL, NULL),
        (5, 1, '河南新闻', NULL, NULL, NULL),
        (6, 1, '山西新闻', NULL, NULL, NULL),
        (7, 1, '河北新闻', NULL, NULL, NULL),
        (8, 6, '郑州新闻', NULL, NULL, NULL),
        (9, 6, '洛阳新闻', NULL, NULL, NULL),
        (10, 9, '中原新闻', NULL, NULL, NULL);

      本文标题:php 递归无限分类

      本文链接:https://www.haomeiwen.com/subject/xyhgittx.html