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 相关文章推荐
图象函数中的中文显示
Oct 09 PHP
深入解析php模板技术原理【一】
Jan 10 PHP
php类常量的使用详解
Jun 08 PHP
安装apache2.2.22配置php5.4(具体操作步骤)
Jun 26 PHP
PHP 伪静态技术原理以及突破原理实现介绍
Jul 12 PHP
php求正负数数组中连续元素最大值示例
Apr 11 PHP
PHP获取文件的MD5值并判断是否被修改的例子
Jun 19 PHP
php.ini中的request_order推荐设置
May 10 PHP
php生成PDF格式文件并且加密
Jun 22 PHP
Laravel中使用FormRequest进行表单验证方法及问题汇总
Jun 19 PHP
PHP回调函数概念与用法实例分析
Nov 03 PHP
PHP设计模式之注册树模式分析
Jan 26 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删除数组中的特定元素的代码
2012/06/28 PHP
PHP手机号码归属地查询代码(API接口/mysql)
2012/09/04 PHP
PHP微信红包API接口
2015/12/05 PHP
ThinkPHP使用Smarty第三方插件方法小结
2016/03/19 PHP
CI框架支持$_GET的两种实现方法
2016/05/18 PHP
thinkPHP模板引擎用法示例
2016/12/08 PHP
PHP连接sftp并下载文件的方法教程
2018/08/26 PHP
使用隐藏的new来创建对象
2011/03/29 Javascript
用Mootools获得操作索引的两种方法分享
2011/12/12 Javascript
利用NodeJS的子进程(child_process)调用系统命令的方法分享
2013/06/05 NodeJs
js点击更换背景颜色或图片的实例代码
2013/06/25 Javascript
使用jQuery异步加载 JavaScript脚本解决方案
2014/04/20 Javascript
浅谈JavaScript数据类型
2015/03/03 Javascript
JavaScript实现点击按钮直接打印
2016/01/06 Javascript
jQuery源码解读之extend()与工具方法、实例方法详解
2017/03/30 jQuery
详解如何理解vue的key属性
2019/04/14 Javascript
layui-tree实现Ajax异步请求后动态添加节点的方法
2019/09/23 Javascript
[04:19]完美世界携手游戏风云打造 卡尔工作室模型介绍篇
2013/04/24 DOTA
json跨域调用python的方法详解
2017/01/11 Python
python学习笔记之列表(list)与元组(tuple)详解
2017/11/23 Python
Python 十六进制整数与ASCii编码字符串相互转换方法
2018/07/09 Python
pygame游戏之旅 载入小车图片、更新窗口
2018/11/20 Python
Python多线程同步---文件读写控制方法
2019/02/12 Python
啥是佩奇?使用Python自动绘画小猪佩奇的代码实例
2019/02/20 Python
Django工程的分层结构详解
2019/07/18 Python
Python数据可视化:泊松分布详解
2019/12/07 Python
tensorflow 实现数据类型转换
2020/02/17 Python
python函数enumerate,operator和Counter使用技巧实例小结
2020/02/22 Python
浅谈numpy中np.array()与np.asarray的区别以及.tolist
2020/06/03 Python
OpenCV Python实现图像指定区域裁剪
2021/03/12 Python
详解python变量与数据类型
2020/08/25 Python
意大利文具和办公产品在线商店:Y-Office
2020/02/27 全球购物
2014年局领导班子自身建设情况汇报
2014/11/21 职场文书
食品质检员岗位职责
2015/04/08 职场文书
学校中层领导培训心得体会
2016/01/11 职场文书
spring cloud eureka 服务启动失败的原因分析及解决方法
2022/03/17 Java/Android