PHP无限分类(树形类)的深入分析


Posted in PHP onJune 02, 2013

PHP无限分类,Google一下就能找到很多相关资料,思路比较拉风的,也是用得比较多的就是分类表至少有id,pid,name三个字段,id自增表分类,pid为父分类,name为分类名,这样就构成了一棵树,如下,算是我查询分类表得到的结果集。

<?php
//模拟PHP无限分类查询结果
return array(
    array(
        'id'=>1,
        'pid'=>0,
        'name'=>'主页'
    ),
    array(
        'id'=>2,
        'pid'=>0,
        'name'=>'新闻'
    ),
    array(
        'id'=>3,
        'pid'=>0,
        'name'=>'媒体'
    ),
    array(
        'id'=>4,
        'pid'=>0,
        'name'=>'下载'
    ),
    array(
        'id'=>5,
        'pid'=>0,
        'name'=>'关于我们'
    ),
    array(
        'id'=>6,
        'pid'=>2,
        'name'=>'天朝新闻'
    ),
    array(
        'id'=>7,
        'pid'=>2,
        'name'=>'海外新闻'
    ),
    array(
        'id'=>8,
        'pid'=>6,
        'name'=>'州官新闻'
    ),
    array(
        'id'=>9,
        'pid'=>3,
        'name'=>'音乐'
    ),
    array(
        'id'=>10,
        'pid'=>3,
        'name'=>'电影'
    ),
    array(
        'id'=>11,
        'pid'=>3,
        'name'=>'小说'
    ),
    array(
        'id'=>12,
        'pid'=>9,
        'name'=>'铃声'
    ),
    array(
        'id'=>13,
        'pid'=>9,
        'name'=>'流行音乐'
    ),
    array(
        'id'=>14,
        'pid'=>9,
        'name'=>'古典音乐'
    ),
    array(
        'id'=>15,
        'pid'=>12,
        'name'=>'热门铃声'
    ),
    array(
        'id'=>16,
        'pid'=>12,
        'name'=>'搞笑铃声'
    ),
    array(
        'id'=>17,
        'pid'=>12,
        'name'=>'MP3铃声'
    ),
    array(
        'id'=>18,
        'pid'=>17,
        'name'=>'128K'
    ),
    array(
        'id'=>19,
        'pid'=>8,
        'name'=>'娱乐新闻'
    ),
    array(
        'id'=>20,
        'pid'=>11,
        'name'=>'穿越类'
    ),
    array(
        'id'=>21,
        'pid'=>11,
        'name'=>'武侠类'
    ),
);
?>

拉风归拉风,但是那些文章提供的无限分类的类相关操作有点挫,直接把对数据库操作也封装进去了。也就是别人要用你这个类,还要跟你建一样的表,真TM恶心。由于项目要用到,所以自己写了一个PHP无限分类的类(也称树形类),没有数据库的操作,只需要实例化的时候传进去结果集,也就是树形数组。再执行leaf方法或navi方法即可得到想要的结果,下面请看源码,看完之后奉上smarty模板引擎的相应的模板递归方法。
<?php
/**
 * Tree 树型类(无限分类)
 *
 * @author Kvoid
 * @copyright http://kvoid.com
 * @version 1.0
 * @access public
 * @example
 *   $tree= new Tree($result);
 *   $arr=$tree->leaf(0);
 *   $nav=$tree->navi(15);
 */
class Tree {
    private $result;
    private $tmp;
    private $arr;
    private $already = array();
    /**
     * 构造函数
     *
     * @param array $result 树型数据表结果集
     * @param array $fields 树型数据表字段,array(分类id,父id)
     * @param integer $root 顶级分类的父id
     */
    public function __construct($result, $fields = array('id', 'pid'), $root = 0) {
        $this->result = $result;
        $this->fields = $fields;
        $this->root = $root;
        $this->handler();
    }
    /**
     * 树型数据表结果集处理
     */
    private function handler() {
        foreach ($this->result as $node) {
            $tmp[$node[$this->fields[1]]][] = $node;
        }
        krsort($tmp);
        for ($i = count($tmp); $i > 0; $i--) {
            foreach ($tmp as $k => $v) {
                if (!in_array($k, $this->already)) {
                    if (!$this->tmp) {
                        $this->tmp = array($k, $v);
                        $this->already[] = $k;
                        continue;
                    } else {
                        foreach ($v as $key => $value) {
                            if ($value[$this->fields[0]] == $this->tmp[0]) {
                                $tmp[$k][$key]['child'] = $this->tmp[1];
                                $this->tmp = array($k, $tmp[$k]);
                            }
                        }
                    }
                }
            }
            $this->tmp = null;
        }
        $this->tmp = $tmp;
    }
    /**
     * 反向递归
     */
    private function recur_n($arr, $id) {
        foreach ($arr as $v) {
            if ($v[$this->fields[0]] == $id) {
                $this->arr[] = $v;
                if ($v[$this->fields[1]] != $this->root) $this->recur_n($arr, $v[$this->fields[1]]);
            }
        }
    }
    /**
     * 正向递归
     */
    private function recur_p($arr) {
        foreach ($arr as $v) {
            $this->arr[] = $v[$this->fields[0]];
            if ($v['child']) $this->recur_p($v['child']);
        }
    }
    /**
     * 菜单 多维数组
     *
     * @param integer $id 分类id
     * @return array 返回分支,默认返回整个树
     */
    public function leaf($id = null) {
        $id = ($id == null) ? $this->root : $id;
        return $this->tmp[$id];
    }
    /**
     * 导航 一维数组
     *
     * @param integer $id 分类id
     * @return array 返回单线分类直到顶级分类
     */
    public function navi($id) {
        $this->arr = null;
        $this->recur_n($this->result, $id);
        krsort($this->arr);
        return $this->arr;
    }
    /**
     * 散落 一维数组
     *
     * @param integer $id 分类id
     * @return array 返回leaf下所有分类id
     */
    public function leafid($id) {
        $this->arr = null;
        $this->arr[] = $id;
        $this->recur_p($this->leaf($id));
        return $this->arr;
    }
}
?>

在smarty中的PHP无限分类的使用方法:
$result=$db->query(……);//这里查询得到结果集,注意结果集为数组
$tree= new Tree($result);
$arr=$tree->leaf(0);
$nav=$tree->navi(15);
$smarty->assign(‘arr',$arr);
$smarty->assign(‘nav',$nav);
$smarty->display(‘test.html');
在smarty模板中这样递归:
<!--导航-->
<div id="navigator">
<{foreach $nav as $n}>
    <{if $n@iteration != $n@last}>
        <{$n.name}> ->
    <{else}>
        <{$n.name}>
    <{/if}>
<{/foreach}>
</div>
<!--树形菜单-->
<div id="menu">
<{function name=menu}>
    <ul>
        <{foreach $data as $entry}>
            <li>
                <span><{$entry.name}></span> <{*注意字段要改成自己的字段哦*}>
            <{if isset($entry.child)}>
                <{call name=menu data=$entry.child}>
            <{/if}>
            </li>
        <{/foreach}>
    </ul>
<{/function}>
<{call name=menu data=$arr}> <{*注意在这里$arr才是模板变量*}>
</div>

当然,你也可以更改递归方法,用你想的标签不受拘束。HTML+PHP混编的递归方法这里就不贴了,我也懒得写,最讨厌混编,看着恶心,在这里推荐一下jake前辈的SpeedPHP框架,由于默认的引擎是smarty,我的这个PHP无限分类完全兼容SP框架。同样的,jquery的treeview插件和下拉菜单插件也完美支持。
对了,建议使用Smarty强大的缓存功能,缓存才是王道。
PHP 相关文章推荐
php抓取https的内容的代码
Apr 06 PHP
php开启安全模式后禁用的函数集合
Jun 26 PHP
应用开发中涉及到的css和php笔记分享
Aug 02 PHP
基于php设计模式中单例模式的应用分析
May 15 PHP
php socket实现的聊天室代码分享
Aug 16 PHP
PHP实现HTTP断点续传的方法
Jun 17 PHP
php实现可逆加密的方法
Aug 11 PHP
学习php设计模式 php实现原型模式(prototype)
Dec 07 PHP
Yii2――使用数据库操作汇总(增删查改、事务)
Dec 19 PHP
基于yaf框架和uploadify插件,做的一个导入excel文件,查看并保存数据的功能
Jan 24 PHP
PHP实现十进制数字与二十六进制字母串相互转换操作示例
Aug 10 PHP
基于php伪静态的实现方法解析
Jul 31 PHP
基于php无限分类的深入理解
Jun 02 #PHP
php curl的深入解析
Jun 02 #PHP
Window 7/XP 安装Apache 2.4与PHP 5.4 的过程详解
Jun 02 #PHP
web站点获取用户IP的安全方法 HTTP_X_FORWARDED_FOR检验
Jun 01 #PHP
获取用户Ip地址通用方法与常见安全隐患(HTTP_X_FORWARDED_FOR)
Jun 01 #PHP
php源代码安装常见错误与解决办法分享
May 28 #PHP
如何批量替换相对地址为绝对地址(利用bat批处理实现)
May 27 #PHP
You might like
ajax实现无刷新分页(php)
2010/07/18 PHP
destoon官方标签大全
2014/06/20 PHP
js解析与序列化json数据(二)序列化探讨
2013/02/01 Javascript
Jquery显示、隐藏元素以及添加删除样式
2013/08/09 Javascript
jQuery学习笔记之 Ajax操作篇(三) - 过程处理
2014/06/23 Javascript
js脚本分页代码分享(7种样式)
2015/08/19 Javascript
JS+CSS实现分类动态选择及移动功能效果代码
2015/10/19 Javascript
Angular 页面跳转时传参问题
2016/08/01 Javascript
JavaScript数组迭代方法
2017/03/03 Javascript
基于JavaScript实现无限加载瀑布流
2017/07/21 Javascript
JS原生数据双向绑定实现代码
2017/08/14 Javascript
微信小程序视图template模板引用的实例详解
2017/09/20 Javascript
vue input输入框关键字筛选检索列表数据展示
2020/10/26 Javascript
vue监听用户输入和点击功能
2019/09/27 Javascript
js实现3D旋转相册
2020/08/02 Javascript
JavaScript实现网页动态生成表格
2020/11/25 Javascript
pymongo中聚合查询的使用方法
2019/03/22 Python
在Qt5和PyQt5中设置支持高分辨率屏幕自适应的方法
2019/06/18 Python
Python的pygame安装教程详解
2020/02/10 Python
tensorflow中tf.reduce_mean函数的使用
2020/04/19 Python
python利用google翻译方法实例(翻译字幕文件)
2020/09/21 Python
Coach澳大利亚官方网站:美国著名时尚奢侈品牌
2017/05/24 全球购物
Jimmy Choo美国官网:周仰杰鞋子品牌
2018/06/08 全球购物
Famous Footwear加拿大:美国多品牌运动休闲鞋店
2018/12/05 全球购物
什么是Assembly(程序集)
2014/09/14 面试题
淘宝活动策划方案
2014/02/06 职场文书
三好学生演讲稿范文
2014/04/26 职场文书
银行优秀员工事迹材料
2014/05/29 职场文书
学校四群教育实施方案
2014/06/12 职场文书
2014年入党积极分子学习三中全会思想汇报
2014/09/13 职场文书
王兆力在市委党的群众路线教育实践活动总结大会上的讲话稿
2014/10/25 职场文书
工作失误检讨书范文
2015/01/26 职场文书
解除租赁合同协议书
2016/03/21 职场文书
求职信:会计求职的写作技巧
2019/04/24 职场文书
Python 文本滚动播放器的实现代码
2021/04/25 Python
Python游戏开发实例之graphics实现AI五子棋
2021/11/01 Python