我的功能比较庞大(一个专题功能中的无限个页面),先说下详细再看代码。
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;
}
}
程序中一共递归了2处,值得一提的是getPPCount()模型方法里的那次递归,引发了一个bug。
如果直接return $getNum,值为null。
而且global $getNum也无效,所以不是局部变量或全局变量的问题。
只有通过赋值给类成员才可用。
至于变量引用这个方法我没试,觉得这样比用类成员解决问题更不靠谱。
所以这样已经是最好的办法了。

![[原创] PHP递归函数实现无限分类 (全代码+数据结构)实例示范 https://blog.img.crazyphper.com/2011/09/sss-300x67.jpg](https://blog.img.crazyphper.com/2011/09/sss-300x67.jpg)
发表回复