konakona
Dream Afar.
konakona

[原创] PHP递归函数实现无限分类 (全代码+数据结构)实例示范

我的功能比较庞大(一个专题功能中的无限个页面),先说下详细再看代码。

topic_info(基础表),topic_page(页面表)

 

基础表结构

CREATE TABLE `topic_info` (
  `t_id` int(11) NOT NULL AUTO_INCREMENT,
  `t_name` varchar(30) NOT NULL,
  `t_start_date` date NOT NULL COMMENT '开始时间',
  `t_end_date` date NOT NULL COMMENT '结束时间',
  `t_keyword` varchar(120) NOT NULL COMMENT '键字关',
  `t_description` varchar(200) NOT NULL COMMENT '述描',
  `t_list_logo` varchar(150) NOT NULL COMMENT '列表小图标',
  `t_overview` varchar(255) NOT NULL,
  `t_urlname` varchar(10) NOT NULL COMMENT '专题url',
  `t_template_dir` varchar(15) NOT NULL COMMENT '模板文件夹名称',
  `t_sort` int(11) NOT NULL DEFAULT '100' COMMENT '排序,数字越小排月前',
  `t_doc` varchar(200) NOT NULL COMMENT '出入境相关文档',
  `mana_id` int(11) NOT NULL COMMENT '作者',
  `last_change_time` datetime NOT NULL COMMENT '后最修改人',
  `last_change_mana_id` int(11) NOT NULL COMMENT '最后修改时间',
  PRIMARY KEY (`t_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='专题列表'

页面表结构

CREATE TABLE `topic_page` (
  `p_id` int(11) NOT NULL AUTO_INCREMENT,
  `p_title` varchar(100) NOT NULL,
  `p_overview` varchar(255) NOT NULL COMMENT '一段小描述可以为空',
  `p_temp_name` varchar(30) NOT NULL COMMENT '模板名',
  `p_index` tinyint(1) NOT NULL DEFAULT '0' COMMENT '如果为1,就是首页,同一个t_id里只允许有一个',
  `p_sort` int(11) NOT NULL DEFAULT '100' COMMENT '排序,1最前',
  `father_p_id` int(11) NOT NULL COMMENT '上级id',
  `mana_id` int(11) NOT NULL,
  `last_change_time` datetime NOT NULL,
  `last_change_mana_id` int(11) NOT NULL,
  `t_id` int(11) NOT NULL COMMENT '所属专题',
  `p_menu_show` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1可见,0不可见',
  PRIMARY KEY (`p_id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8

其实接下来的程序中,并不会过多的使用到基础表,但也放出来,给大家了解下为什么接下来会有t_id这些非topic_page表的东西。

程序部分用的是Thinkphp2.1,懒的脱离出来用原始php写了,大家有一定php基础的人一定看得懂这种封装。

但有一点必须注意:
这里的递归最好用class,因为单纯的function无法满足,有bug(php的bug)。

//控制器
public function index() {
        $id = intval ( $_GET ['id'] );
        $this->assign ( "t_id", $id );
        $page = $_POST ['pageNum'] > '0' ? intval ( $_POST ['pageNum'] ) - 1 : 0;
        $numPerPage = intval ( $_POST ['numPerPage'] ) == '0' ? 20 : intval ( $_POST ['numPerPage'] );
        $page = $page * $numPerPage;
        $this->assign ( 'totalCount', $this->pageModel->getList ( true, 0, 0, "t_id = " . $id ) ); //计算总数
        $this->assign ( 'currentPage', $_POST ['pageNum'] ); //当前页
        

        $list = $this->pageModel->where ( 'father_p_id = 0' )->order ( 'p_sort asc' )->select ();
        $html = '';
        foreach ( $list as $k => $v ) {
            $html .= "{$v['p_id']}";
            if ($v ['p_index'] === 1) {
                $html .= '[主页面]';
            }
            $html .= "{$v['p_title']}
            			{$v['label_count']}
            			{$v['p_temp_name']}
            			
            			" . D ( 'user.admin' )->getName ( $v ['mana_id'] ) . "
            			{$v['last_change_time']}
            			" . D ( 'user.admin' )->getName ( $v ['last_change_mana_id'] ) . "
            			";
            //通过这个函数递归获迭代数组
            $html .= $this->pageModel->getSonList ( $v );
        }
        $this->assign ( "html", $html );
        $this->display ( "topic:page_control" );
    }
//控制器里用到的$this->pageModel模型部分代码:
/**
     * 获取所有p_id的子页面,并递归这些子页面的子子页面直到没有为止,并组成HTML
     * @param $array
     */
    public function getSonList($array) {
        //
        $temp_list = $this->field ( 't_id,father_p_id,p_id,p_title,p_temp_name,p_sort' )->where ( 'father_p_id = ' . $array ['p_id'] )->order ( 'p_sort asc' )->select ();
        //如果有子页面数据,则递归函数,直到拿到所有的子页面为止
        if (count ( $temp_list ) > 0) {
            foreach ( $temp_list as $temp_k => $temp_v ) {
                //用于存储当前页面的子页面总数
                //因为当前页面也有可能是子页面,所以需要向上抓取。
                //通过当前数据的父页面字段father_p_id不断往上递归,并记录递归次数
                $this->getPPCount ( $temp_v ['father_p_id'], $temp_v ['p_id'] );
                
                //将当前子页面的数据组织成html
                $html .= "{$temp_v['p_id']}
                            ";
                for($i = 0; $i < $this->pageToFatherCount; $i ++) {
                    $html .= " 
|-
"; } $html .= "{$temp_v['p_title']} {$temp_v['label_count']} {$temp_v['p_temp_name']} " . D ( 'user.admin' )->getName ( $temp_v ['mana_id'] ) . " {$temp_v['last_change_time']} " . D ( 'user.admin' )->getName ( $temp_v ['last_change_mana_id'] ) . " "; //递归,因为程序有理由认为子页面还有其他子页面 $html .= $this->getSonList ( $temp_v ); } return $html; } } /** * 获取p_id的子页面总数 * @param $p_id * @param $num 第一次进来肯定是距离为1 */ private function getPPCount($father_p_id, $p_id, $getNum = 1) { if (! $p_id) return false; ///通过$p_id(本身是别人的fahter_p_id),获得其他使用它作为$father_p_id的值,如果有,就递归继续查询。 $result = $this->where ( 'p_id = ' . $father_p_id )->find (); if ($result ['father_p_id'] != 0) { $this->getPPCount ( $result ['father_p_id'], $result ['p_id'], $getNum + 1 ); } else { $this->pageToFatherCount = $getNum; } }

https://blog.img.crazyphper.com/2011/09/sss-300x67.jpg

最终效果如图,无限个页面。

程序中一共递归了2处,值得一提的是getPPCount()模型方法里的那次递归,引发了一个bug
如果直接return $getNum,值为null。
而且global $getNum也无效,所以不是局部变量或全局变量的问题。
只有通过赋值给类成员才可用。
至于变量引用这个方法我没试,觉得这样比用类成员解决问题更不靠谱。

所以这样已经是最好的办法了。

赞赏
#
首页      程序开发      PHP      [原创] PHP递归函数实现无限分类 (全代码+数据结构)实例示范

团哥

文章作者

继续玩我的CODE,让别人说去。 低调,就是这么自信。

konakona

[原创] PHP递归函数实现无限分类 (全代码+数据结构)实例示范
我的功能比较庞大(一个专题功能中的无限个页面),先说下详细再看代码。 topic_info(基础表),topic_page(页面表)   基础表结构 CREATE TABLE `topic_info` ( `t_id` …
扫描二维码继续阅读
2011-09-08