php无限分类源码,php 递归无限分类

参考

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

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

个人理解 。其实递归分类的本质是

1.把一个表里面的所有数据都取出来

2-1.如果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'));

}

186317850_1_20200324102855978.png

数据表

186317850_2_20200324102859557.png

dd($data)结果

186317850_3_20200324102900650.png

dd($newClass,查看getList()函数的执行顺序)

186317850_4_20200324102902682.png

echo $key."\n"结果

186317850_5_20200324102903416.png

print_r($val)."\n";结果

186317850_6_20200324102906619.png

$newClass = $this->getList($data);

dd($newClass);

报错

186317850_7_20200324102909822.png

dd($newClass);结果

186317850_8_20200324102912447.png

getList()函数中,如果$result不加传指符$,dd($newClass)结果)

3.前台直接遍历输出就可以了。

@foreach($newClass as $v)

{{$v['name']}}

@endforeach

186317850_9_20200324102913463.png

效果图

数据结构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

@foreach($newClass as $v)

{{$v['name']}}

@endforeach

还有一种方法:不使用传指符,而是把接收的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);

根据层级添加空格

/**

* 格式化用户的菜单输出数据

* @param $menus \App\Models\System\Menu[]

* @param int $parentId 父节点ID

* @return array

*/

protected function formatRoleMenu($menus, $parentId = 0, $adds='')

{

static $arr = [];

$j = $k = '';

$j .= ' ├─ ';

$k = $adds ? ' ├─ ' : '';

$depth = $adds ? $adds . $j : '';

$space = ' ';

foreach ($menus as $key => $menu) {

if ($menu->getParentId() == $parentId) {

$arr[$key] = [

'menu_id' => $menu->getId(),

'parent_id' => $menu->getParentId(),

'title' => $depth . $menu->getTitle(),

'icon' => $menu->getIcon(),

'route' => $menu->getRoute(),

'is_hide' => $menu->getIsHide(),

];

unset($menus[$key]);

$this->formatRoleMenu($menus, $menu->getId(), $adds . $k . $space);

}

}

return $arr;

}

优化之后

protected function formatRoleMenu($menus, $parentId = 0, $deep = -1)

{

static $arr = [];

$deep += 1;

foreach ($menus as $key => $menu) {

if ($menu->getParentId() == $parentId) {

$arr[$key] = [

'menu_id' => $menu->getId(),

'parent_id' => $menu->getParentId(),

'title' => $depth . $menu->getTitle(),

'icon' => $menu->getIcon(),

'route' => $menu->getRoute(),

'is_hide' => $menu->getIsHide(),

// 可能str_repeat()函数不能直接识别空格,所以此处使用   代替一个空格

'depth' => str_repeat('    ' . '├─ ', $deep),

];

unset($menus[$key]);

=

$this->formatRoleMenu($menus, $menu->getId(), $adds . $k . $space);

}

}

return $arr;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值