PHP实现无限极分类的两种方式
PHP实现无限极分类的两种方式,递归和引用面试的时候被问到无限极分类的设计和实现,比较常见的做法是在建表的时候,增加一个PID字段用来区别自己所属的分类$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' => '武安市'),);1234567891011数据在数据库中存储大概是这个样子,怎么实现无限极递归呢,有两种常用的做法,递归和引用算法递归算法 /* * 递归实现无限极分类 * param $array 分类数据 * param $pid 父ID * param $level 分类级别 * return $list 分好类的数组 直接遍历即可 $level可以用来遍历缩进 */ function getTree($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 getTree($array, $value'id', $level+1); return $list; /* * 获得递归完的数据,遍历生成分类 */ $array = getTree($array); foreach($array) as $value echo str_repeat('-', $value'level'), $value'name'.'<br />' /输出结果 无限极分类实现ok河北省-邯郸市-永年区-武安市北京市-朝阳区-望京-酒仙桥-通州区123456789101112131415161718192021222324252627282930313233343536373839404142434445464748引用算法function generateTree($array) /第一步 构造数据 $items = array(); foreach($array as $value) $items$value'id' = $value; /第二部 遍历数据 生成树状结构 $tree = array(); foreach($items as $key => $value) if(isset($items$item'pid') $items$item'pid''son' = &$items$key; else $tree = &$items$key; return $tree;/经过第一步 数据变成了这样乐淘棋牌http:/www.letaoqpyx.comArray( 1 => Array ( id => 1 pid => 0 name => 河北省 children => Array ( ) ) 2 => Array ( id => 2 pid => 0 name => 北京市 children => Array ( ) ) 3 => Array ( id => 3 pid => 1 name => 邯郸市 children => Array ( ) ) 4 => Array ( id => 4 pid => 2 name => 朝阳区 children => Array ( ) ) 5 => Array ( id => 5 pid => 2 name => 通州区 children => Array ( ) ) 6 => Array ( id => 6 pid => 4 name => 望京 children => Array ( ) ) 7 => Array ( id => 7 pid => 4 name => 酒仙桥 children => Array ( ) ) 8 => Array ( id => 8 pid => 3 name => 永年区 children => Array ( ) ) 9 => Array ( id => 9 pid => 1 name => 武安市 children => Array ( ) )/第一步很容易就能看懂,就是构造数据,现在咱们仔细说一下第二步 $tree = array(); /遍历构造的数据 foreach($items as $key => $value) /如果pid这个节点存在 if(isset($items$value'pid') /把当前的$value放到pid节点的son中 注意 这里传递的是引用 为什么呢? $items$value'pid''son' = &$items$key; else $tree = &$items$key; /这个方法的核心在于引用,php变量默认的传值方式是按指传递/也就是说 假如说 遍历顺序是 河北省 邯郸市 当遍历到河北省时 会把河北省放到tree中 遍历到邯郸市时 会把邯郸市放到河北省的子节点数组中 但是! 这会儿的tree数组中 河北省已经放进去了 根据php变量按值传递的规则 你并没有更改tree数组中的河北省的数据 所以这里用到了引用传递/当你对河北省做更改时,tree数组中的河北省也一并做了更改 下面我们做个实验 我们把引用传递去掉,看一下结果移动电玩城http:/www.44226.net/使用普通传值输出结果 Array( 0 => Array ( id => 1 pid => 0 name => 河北省 ) 1 => Array ( id => 2 pid => 0 name => 北京市 )/可以看到 只有河北省和北京市输出