php无限极分类
这里首先介绍一下,什么是无限极分类?
无限极分类简单点说就是一个类可以分成多个子类,然后一个子类又可以分另外多个子类这样无限分下去,就好象windows可以新建一个文件夹,然后在这个文件夹里又可以建一些个文件夹,在文件夹底下还可以建一些文件夹一样
那PHP又是如何实现它的无限分类的呢?如何把它的各个分类一一列出来呢?
首先,我们来假设有这样一个数组
$arr = array(
0=>array(
'cid'=>1,
'pid'=>0,
'name'=>'亚洲',
),
1=>array(
'cid'=>2,
'pid'=>0,
'name'=>'北美洲',
),
2=>array(
'cid'=>3,
'pid'=>1,
'name'=>'中国',
),
3=>array(
'cid'=>4,
'pid'=>2,
'name'=>'美国',
),
4=>array(
'cid'=>5,
'pid'=>3,
'name'=>'北京',
),
5=>array(
'cid'=>6,
'pid'=>3,
'name'=>'河北',
),
6=>array(
'cid'=>7,
'pid'=>5,
'name'=>'东城区',
),
7=>array(
'cid'=>8,
'pid'=>5,
'name'=>'海淀区',
),
);
我们这里需要一个类似这样的展示效果如图
如果我们要想将这个数组如上图般很直观的表现出来的话就需要用php的递归来实现,那么怎么实现呢?看下面的核心代码
复制代码
private function GetTree($arr,$pid,$step){
global $tree;
foreach($arr as $key=>$val) {
if($val['pid'] == $pid) {
$flg = str_repeat('└―',$step);
$val['name'] = $flg.$val['name'];
$tree[] = $val;
$this->GetTree($arr , $val['cid'] ,$step+1);
}
}
return $tree;
}
复制代码
然后我们只需要写一个调用的代码就好
$newarr = $this->GetTree($arr, 0, 0);
根据子类id查找出所有父级分类信息(yii2框架中)
方法一:
public static function get_parent_list($arr,$id){
//$arr 所有分类列表
//$id 父级分类id
static $list=array();
foreach($arr as $u){
if($u['id']== $id){//父级分类id等于所查找的id
$list[]=$u;
if($u['parent_id']>0){
self::get_parent_list($arr,$u['parent_id']);
}
}
}
return $list;
}
这样可以把分类信息储存到缓存里,而不需要递归查询。
方法二:递归查询取分类信息
public static function get_parents($id){
static $list = [];
$cat_data = Category::findOne($id)->toarray();
if($cat_data){
$list[] = $cat_data;
$id = $cat_data['parent_id'];
if($cat_data['parent_id'] > 0){
self::get_parents($id);
}
}
return $list;
}
由于需要实现无限级分类,所以我们需要知道它的子栏目有什么?
最后实现的数组是这样的形式:
[php] view plain copy
Array
(
[0] => Array
(
[category_id] => 1
[category_name] => 关于我
[category_pid] => 0
[category_addtime] => 0
[category_order] => 0
)
[1] => Array
(
[category_id] => 2
[category_name] => 生活随笔
[category_pid] => 0
[category_addtime] => 0
[category_order] => 0
)
[2] => Array
(
[category_id] => 3
[category_name] => 文章类别
[category_pid] => 0
[category_addtime] => 0
[category_order] => 0
[category_child] => Array
(
[0] => Array
(
[category_id] => 4
[category_name] => Linux服务器
[category_pid] => 3
[category_addtime] => -28800
[category_order] => 1
[category_child] => Array
(
[0] => Array
(
[category_id] => 5
[category_name] => linux优化
[category_pid] => 4
[category_addtime] => 0
[category_order] => 0
)
[1] => Array
(
[category_id] => 6
[category_name] => 虚拟化
[category_pid] => 4
[category_addtime] => 1478228220
[category_order] => 0
)
[2] => Array
(
[category_id] => 7
[category_name] => Mysql优化与开发
[category_pid] => 4
[category_addtime] => 1478188800
[category_order] => 0
)
[3] => Array
(
[category_id] => 8
[category_name] => 高可用与虚拟化
[category_pid] => 4
[category_addtime] => 1478394120
[category_order] => 0
)
)
)
[1] => Array
(
[category_id] => 15
[category_name] => Mysql
[category_pid] => 3
[category_addtime] => 1480555980
[category_order] => 0
[category_child] => Array
(
[0] => Array
(
[category_id] => 16
[category_name] => 优化
[category_pid] => 15
[category_addtime] => 1480555980
[category_order] => 0
)
[1] => Array
(
[category_id] => 17
[category_name] => Sql编程
[category_pid] => 15
[category_addtime] => 1480556040
[category_order] => 8
)
)
)
)
)
)
那么我们从数据库中取出来的二维数组如何才能变成上面这样的数组呢?
举例:
我们要把下面这个二维数组实现成上面那种形式。
[php] view plain copy
$arr=array(
array('id'=>'1','name'=>'北京','pid'=>'0'),
array('id'=>'2','name'=>'上海','pid'=>'0'),
array('id'=>'3','name'=>'浦东','pid'=>'2'),
array('id'=>'4','name'=>'朝阳','pid'=>'1'),
array('id'=>'5','name'=>'广州','pid'=>'0'),
array('id'=>'6','name'=>'三里屯','pid'=>'4'),
array('id'=>'7','name'=>'广东','pid'=>'5'),
array('id'=>'8','name'=>'三里','pid'=>'4'),
array('id'=>'10','name'=>'小胡同','pid'=>'8')
);
第一种方法:利用数组的索引与主键的id号相同来查找子栏目,首先为数组加上索引:
[php] view plain copy
$arr=array(
1=>array('id'=>'1','name'=>'北京','pid'=>'0'),
2=>array('id'=>'2','name'=>'上海','pid'=>'0'),
3=>array('id'=>'3','name'=>'浦东','pid'=>'2'),
4=>array('id'=>'4','name'=>'朝阳','pid'=>'1'),
5=>array('id'=>'5','name'=>'广州','pid'=>'0'),
6=>array('id'=>'6','name'=>'三里屯','pid'=>'4'),
7=>array('id'=>'7','name'=>'广东','pid'=>'5'),
8=>array('id'=>'8','name'=>'三里','pid'=>'4'),
10=>array('id'=>'10','name'=>'小胡同','pid'=>'8')
);
利用索引的下标,判断该栏目是否存在父栏目,如果存在就把该栏目放到父栏目的son子数组里面
[php] view plain copy
function generateTree($items){
$tree = array();
foreach($items as $item){
//判断是否有数组的索引==
if(isset($items[$item['pid']])){ //查找数组里面是否有该分类 如 isset($items[0]) isset($items[1])
$items[$item['pid']]['son'][] = &$items[$item['id']]; //上面的内容变化,$tree里面的值就变化
}else{
$tree[] = &$items[$item['id']]; //把他的地址给了$tree
}
}
return $tree;
}
上面这个程序有一个主要问题,数组的索引是我们手动添加的?那我们可不可以自动添加数组索引呢?当然可以,下面这个程序就实现了,自动为数组添加索引然后再把子栏目放到父栏目的son数组中,思想和上面的程序是一样的
[php] view plain copy
function make_tree($list,$pk='id',$pid='pid',$child='_child',$root=0){
$tree=array();
$packData=array();
foreach ($list as $data) {
<span style="white-space:pre"> </span>//转换为带有主键id的数组
$packData[$data[$pk]] = $data; //$packData[1]=$data; $packData[2]=$data
}
foreach ($packData as $key =>$val){
if($val[$pid]==$root){ //代表跟节点
$tree[]=& $packData[$key];
}else{
//找到其父类
$packData[$val[$pid]][$child][]=& $packData[$key];
}
}
return $tree;
}
第二种方法:使用递归来查找子栏目
思想:使用递归来查找每个栏目中的子栏目,直到找到最后一个子栏目以后再一层层往外运行调试的话,可以打印
tree看一下,会发现,第一个打印的不是最后一个子栏目,而是三里屯,然后是北京的最后一个子栏目小胡同,这个是因为递归的时候,三里屯和三里在一个层级,三里屯下面没有子栏目直接跳出循环输出了,所以三里屯会在第一个
tree中,,为了方便理解,可以打印$tree去观察数组的变化
[php] view plain copy
array('id'=>'6','name'=>'三里屯','pid'=>'4'),
[php] view plain copy
function make_tree1($list,$pk='id',$pid='pid',$child='_child',$root=0){
$tree=array();
foreach($list as $key=> $val){
if($val[$pid]==$root){
//获取当前$pid所有子类
unset($list[$key]);
if(! empty($list)){
$child=make_tree1($list,$pk,$pid,$child,$val[$pk]); //来来来 找北京的子栏目 递归 空
if(!empty($child)){
$val['_child']=$child;
}
}
$tree[]=$val;
}
}
return $tree;
}
为了更好的理解递归,大家可以找一个小程序测试一下例如下面这个求和的程序
大家可以分析一下$n的输出从2,3 …..10,而不是从10,9—-2,我从这个程序才理解了一下上面那个程序的递归是如何实现的,总之:递归是很有意思的一个东西,希望大家好好理解
[php] view plain copy
function sum($n){
$a=0;
if($n>1){
$a=sum($n-1)+$n;
/*if($n>5){
echo "$n <br />" ;
}*/
echo "$n<br />";
}else{
$a=1;
}
return $a;
}
echo sum(10);
根据父id获得所有下级子类id的数据
#$id = 父级id, $array = 所有分类
public function getSon($id,$array){
static $list;
foreach ($array as $k => $v) {
if($v['parent_id'] == $id){
$list[] = $array[$k];
self::getSon($v['id'],$array);
}
}
return $list;
}