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 相关文章推荐
BBS(php &amp; mysql)完整版(五)
Oct 09 PHP
转换中文日期的PHP程序
Oct 09 PHP
php header()函数使用说明
Jul 10 PHP
PHP 命令行参数详解及应用
May 18 PHP
PHP gbk环境下json_dencode传送来的汉字
Nov 13 PHP
PHP 5.3新增魔术方法__invoke概述
Jul 23 PHP
php实现的支持imagemagick及gd库两种处理的缩略图生成类
Sep 23 PHP
PHP与Ajax相结合实现登录验证小Demo
Mar 16 PHP
php自动提交表单的方法(基于fsockopen与curl)
May 09 PHP
ThinkPHP中获取指定日期后工作日的具体日期方法
Oct 14 PHP
使用Zookeeper分布式部署PHP应用程序
Mar 15 PHP
tp5修改(实现即点即改)
Oct 18 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
PHP的SQL注入过程分析
2012/01/06 PHP
php的mssql数据库连接类实例
2014/11/28 PHP
PHP基于SimpleXML生成和解析xml的方法示例
2017/07/17 PHP
PHP实现正则匹配所有括号中的内容
2018/06/22 PHP
Yii框架日志记录Logging操作示例
2018/07/12 PHP
PHP实现微信退款的方法示例
2019/03/26 PHP
document.getElementById的简写方式(获取id对象的简略写法)
2010/09/10 Javascript
js调试工具console.log()方法查看js代码的执行情况
2014/08/08 Javascript
jQuery实现类似淘宝网图片放大效果的方法
2015/07/08 Javascript
javascript实现下班倒计时效果的方法(可桌面通知)
2015/07/10 Javascript
关于js函数解释(包括内嵌,对象等)
2016/11/20 Javascript
jQuery复合事件用法示例
2017/06/10 jQuery
请求时token过期自动刷新token操作
2020/09/11 Javascript
基于javascript实现放大镜特效
2020/12/03 Javascript
在Python中使用全局日志时需要注意的问题
2015/05/06 Python
Python使用os模块和fileinput模块来操作文件目录
2016/01/19 Python
使用python实现rsa算法代码
2016/02/17 Python
Django 实现下载文件功能的示例
2018/03/06 Python
python 多维切片之冒号和三个点的用法介绍
2018/04/19 Python
python遍历一个目录,输出所有的文件名的实例
2018/04/23 Python
Django保护敏感信息的方法示例
2019/05/09 Python
pytorch加载自定义网络权重的实现
2020/01/07 Python
python 字符串的驻留机制及优缺点
2020/06/19 Python
Django路由层URLconf作用及原理解析
2020/09/24 Python
使用CSS3来实现滚动视差效果的教程
2015/08/24 HTML / CSS
html5 Canvas画图教程(1)—画图的基本常识
2013/01/09 HTML / CSS
聚网科技C++面试笔试题
2015/09/01 面试题
幼儿园父亲节活动方案
2014/03/11 职场文书
公司授权委托书范本
2014/04/03 职场文书
乡领导班子四风问题对照检查材料
2014/09/25 职场文书
学习焦裕禄观后感
2015/06/09 职场文书
污染环境建议书
2015/09/14 职场文书
“学党章、守党纪、讲党规”学习心得体会
2016/01/14 职场文书
QT与javascript交互数据的实现
2021/05/26 Javascript
Python天气语音播报小助手
2021/09/25 Python
Django框架中表单的用法
2022/06/10 Python