konakona
[原创] PHP递归函数实现无限分类 (全代码+数据结构)实例示范
[原创] 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 .= " http://bbs.phpchina.com/images/default/tree_linemiddle.gif";
                }
                
                $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;
        }
    }

http://blog.crazyphper.com/wp-content/uploads/2011/09/sss-300x67.jpg
最终效果如图,无限个页面。

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

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

赞赏
首页      程序开发      PHP      [原创] PHP递归函数实现无限分类 (全代码+数据结构)实例示范
https://secure.gravatar.com/avatar/3b712b34a0e1b689cfb524c9c6bcdc47?s=256&r=g

团哥

文章作者

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

发表评论

textsms
account_circle
email

  • https://secure.gravatar.com/avatar/564d6bd6e577a0e1859a58a0aaf82c5f?s=80&r=g

    嘛 – – 这是我的。。。
    private function __get_type_struct($tid, $lid, $level, $hierprefix)
    {
    $rst = array();

    /** Hierarchy string */
    $last = $hierprefix . “┗”;
    $not_last = $hierprefix . “┣”;

    /** Gat data */
    $i = 0;
    $query = $this->db->where(array(“fatherid” => $tid))->order_by(“order”, “asc”)->get(“type”);
    foreach($query->result() as $row)
    {
    $next_herprefix = $hierprefix . (($i == $query->num_rows – 1) ? ”  ” : “┃”);

    $rst[$i] = (array)$row;
    $rst[$i][“child”] = $this->__get_type_struct($rst[$i][“tid”], $lid, $level + 1, $next_herprefix);
    $rst[$i][“child_count”] = count($rst[$i][“child”]);
    $rst[$i][“href”] = $this->config->item(“base_url”) . “/x_” . $rst[$i][“typeurl”];
    if($rst[$i][“issingle”] == 1) $rst[$i][“href”] .= $this->config->item(“url_suffix”);

    /** The EX type name of it’s language */
    $ex = $this->get_typename_ex($rst[$i][“tid”], $lid, NULL);
    if($ex != NULL) $rst[$i][“typename”] = $ex;

    /** Hierarchy name */
    $rst[$i][“hiername”] = (($i == $query->num_rows – 1) ? $last : $not_last) . $rst[$i][“typename”];
    $rst[$i][“hierprefix”] = ($i == $query->num_rows – 1) ? $last : $not_last;

    $i++;
    }

    return $rst;
    }

    /**
    *
    * @param $lid
    * @return
    */
    public function get_type_struct($lid)
    {
    /** ROOT INFORMATION */
    $struct[“tid”] = -1;
    $struct[“issingle”] = 1;
    $struct[“fatherid”] = -100;
    //$struct[“lid”] = $lid;
    $struct[“index_template_file”] = “content_index”;
    $struct[“list_template_file”] = “content_list”;
    $struct[“content_template_file”] = “content_content”;
    $struct[“typeurl”] = “…”;
    $struct[“group”] = -1;
    $struct[“order”] = 0;
    $struct[“typename”] = “[ROOT]”;
    $struct[“hiername”] = “[ROOT]”;
    $struct[“hierprefix”] = “”;
    $struct[“href”] = $this->config->item(“base_url”);

    $struct[“child”] = $this->__get_type_struct(-1, $lid, 1, “”);
    $struct[“child_count”] = count($struct[“child”]);
    //dump($struct);

    return $struct;
    }

    public function __get_type_struct_array($struct)
    {
    /** COPY CURRENT ONE */
    $this->type_struct_array[$this->type_struct_array_count] = $struct;
    unset($this->type_struct_array[$this->type_struct_array_count][“child”]);
    unset($this->type_struct_array[$this->type_struct_array_count][“child_count”]);

    $this->type_struct_array_count++;

    /** COPY CHILDREN */
    for($i = 0; $i __get_type_struct_array($struct[“child”][$i]);
    }
    }

    public function get_type_struct_array($lid)
    {
    $this->type_struct_array = array();
    $this->type_struct_array_count = 0;

    $struct = $this->get_type_struct($lid);
    $this->__get_type_struct_array($struct);

    return $this->type_struct_array;
    }

    8年前回复

konakona

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