Home >php教程 >php手册 >php无限分类代码与原理

php无限分类代码与原理

WBOY
WBOYOriginal
2016-05-25 16:51:251084browse

第一分类(父分类)-->第二分类(子分类)-->第三分类(孙分类),这种亲缘分类越多,程序和数据库的控制就越加的复杂困难.在同一级的分类处理和控制是非常的简单的,因为只需要一个数据库来记载这一级的分类就行了,如:系统,新闻等分类,在这一级上处理是很简单的,但对一个网站来说一级分类是不够的,还需要再分类

我们建一个表"class"

CREATE TABLE `class` ( 
  `id` int(11) NOT NULL auto_increment COMMENT '分类id', 
  `f_id` int(11) NOT NULL COMMENT '父id', 
  `name` varchar(25) collate gbk_bin NOT NULL COMMENT '分类名称', 
  PRIMARY KEY  (`id`) 
) ENGINE=MyISAM  DEFAULT CHARSET=gbk COLLATE=gbk_bin AUTO_INCREMENT=1 ;

首先我们往数据库里插入'新闻'这个大分类,因为'新闻'是最大分类,上面没有父类了,所以我把它的f_id设置为0。

INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(1, 0, '新闻');   //id这个字段是自动增长的,可以不写值

然后我们再往数据库里插入'PHP新闻'这个分类,它的父类'新闻'的id是1,所以它的f_id设置为1。

INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(2, 1, 'PHP新闻');

然后我们再往数据库里插入'PHP6.0出来了'这个分类,它的父类'PHP新闻'的id是2,所以它的f_id设置为2。

INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(3, 2, 'PHP7.0出来了');

同理,我们可以这样一直往下插入分类,也就达到了无限分类,我们可以发现插入一个分类的原则关键是找到这个分类的父类的id,然后作为这个分类的f_id字段的值。

假设要插入跟'新闻'同一个级别的分类'技术',也就是说它也是最大分类,上面没有父类了,那么它的f_id也设置为0;

INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(4, 0, '技术');

在'技术'下面又有一个分类'PHP技术',那么我们怎么插入呢,首先找到'PHP技术'的父类'技术'的id,然后作为自己的f_id字段的值。

INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(5, 4, 'PHP技术');

看到这里,想必大家应该都明白怎么往数据库里插入各个分类了,就不再举例了,我们已经知道如何往数据库里插入各个分类了,那又如何把各个分类罗列出来呢?

<?php
header("Content-type:text/html;charset=utf-8");
$db = new mysqli("localhost", "root", "", "news_php100"); //实例化一个数据库连接。使用这个前一定要确保已经加载了mysqli类库,或者用mysql_connect这个方式连接。
if (mysqli_connect_errno()) {
    echo "链接失败:" . mysqli_connect_error();
    exit();
}
$db->query("set names utf8");
$result = $db->query("select name from class where f_id=0"); //查找f_id=0的分类,也就是查找每一个大类。
while ($row = $result->fetch_assoc()) {
    echo $row[&#39;name&#39;] . "<br>"; //这样就把每个大类循环出来了。
    
}
//同样我们可以把新闻的子类循环出来。
$result = $db->query("select * from class where f_id=1"); //查找f_id=1的分类,也就是查找&#39;新闻&#39;的子类。
while ($row = $result->fetch_assoc()) {
    echo $row[&#39;name&#39;] . " 
"; //这样就把&#39;新闻&#39;的子类循环出来了。注意:只是子类,不包括孙子类。
    
}
?>

写到这里,我们会发现一个问题,如果这个分类是10级分类,难道我们要写10个循环把它每个子类循环出来?如果是更多级分类呢,这样写显然是不现实的。

那又有什么办法解决呢?我们可以写一个递归的函数,把f_id作为参数传入,不断循环每一个f_id的值,也就是说把每一个f_id值的子类循环出来。

首先我们把各个分类的值保存在一个二维数组中,在下面的递归函数里有用。

<?php
$result = $db->query("select * from class");
while ($row = $result->fetch_assoc()) {
    $arr[] = array(
        $row[id],
        $row[f_id],
        $row[name]
    ); //每一行保存一个分类的id,f_id,name的信息。
    
}
function fenlei($f_id = 0) { //$f_id初始化为0,也就是从最大分类开始循环.
    global $arr; //声明$arr为全局变量才可在函数里引用。
    for ($i = 0; $i < count($arr); $i++) { //对每个分类进行循环。
        if ($arr[$i][1] == $f_id) { //$arr[$i][1]表示第$i+1个分类的f_id的值。开始$f_id=0,也就是把f_id=0的分类输出来。
            echo $arr[$i][2] . "<br>"; //$arr[$i][1]表示第$i+1个分类的name的值。
            fenlei($arr[$i][0]); //$arr[$i][1]表示第$i+1个分类的id的值。进行递归,也就是把自己的id作为f_id参数把自己的子类再循环出来。
            
        }
    }
}
?>

在介绍这个功能前,先介绍一下 explode( ) 这个函数,这是个字串处理函数,用来分解字串的,具体的用法,例:分解"0:1:2:3:4"里的数字

$val="0:1:2:3:4"; 

$rid=explode(":",$val);

经过 explode()函数处理,$val 内的所有数字都分解到 $rid 数组中了,要引用时只需打印:echo "$rid[0],$rid[1],$rid[2]..."; 就行了.explode()函数在整个分类处理中起着非常重要的作用,好现在开始介绍无现分类的程序控制.

可以假设个总分类 0 ,所有的分类都是它的子孙分类,现在来建立第一个分类"系统",来看看它在数据库的存储形式:

id | uid | type | rout_id | rout_char 

1 | 0 | 系统 | 0:1 | 系统

接着又在下面分"Linux":

id | uid | type | rout_id | rout_char 

2 | 1 | Linux| 0:1:2 | 系统:Linux

以上就是数据库存储的形式,现在就来完成 php 的代码,这与论坛的代码很相似,我们所要做的就是将分类的 id 放入 uid,而父分类的 uid 就放 0,下面来看看代码:

<?php
//设置默认页
if (emptyempty($func)) $func == "showtype";
//设置父分类的 uid
if (emptyempty($uid)) $uid = 0;
//数据库存储************************************************
if ($func == "save"):
    $fields = "";
    $values = "";
    if ($id != "") {
        $fields.= ",id";
        $values.= ",$id";
    }
    if ($uid != "") {
        $fields.= ",uid";
        $values.= ",$uid";
    }
    if ($type != "") {
        $fields.= ",type";
        $values.= ","$type"";
    }
    if ($route_id == "") {
        //取得父分类的 route_id
        if ($uid != 0) {
            $result = mysqlquery("select * from type where id=$uid");
            $route_id = mysql_result($result, 0, "route_id");
        } else {
            $routr_id = "0";
        }
        $fields.= ",route_id";
        //形成自己的 route_id
        $route_id = "$route_id:$id";
        $values.= ","$route_id"";
    }
    //形成自己的 route_char
    if ($route_char != "") {
        $fields.= ",route_char";
        $route_char = "$route_char:$type";
        $values.= ","$route_char"";
    } else {
        $fields.= ",route_char";
        $route_char = $type;
        $values.= ","$route_char"";
    }
    $fields = substr($fields, 1, strlen($fields) - 1);
    $values = substr($values, 1, strlen($values) - 1);
    $result = mysqlquery("insert into type ($fields) values ($values)"); . . .
endif; /* end save */
//分类上传************************************************
if ($func == "createtype"):
    //取得自己的 id
    $result = mysqlquery("select * from type order by  
id desc");
    $num = mysql_numrows($result);
    if (!emptyempty($num)) {
        $cat = mysql_result($result, 0, "id");
    } else {
        $cat = 0;
    }
    //判断分类的状态
    if ($uid != 0) {
        $result = mysql_query("select * from type where id=$uid");
        $type = mysql_result($result, 0, "type");
        $route_char = mysql_result($result, 0, "route_char");
    } else {
        $type = "父分类";
    }
    echo "<FORM ACTION="$PHP_SELF ? func = save" METHOD=POST>";
    echo "<table>";
    echo "<tr><td>所属类别:$type</td></tr>";
    echo "<tr><td>创建分类:<input type=text name="type" SIZE=10 MAXLENGTH=100></td></tr>";
    echo "<tr><td>";
    $cat = $cat + 1;
    echo "<input type=hidden name=id value="$cat">";
    echo "<input type=hidden name=uid value="$uid">";
    echo "<input type=hidden name=route_char value="$route_char">";
    echo "<INPUT TYPE=submit NAME="Save" VALUE="保存"></td></tr>";
    echo "</table>";
    echo "</form>";
endif; /* end createtype */
//显示分类************************************************
if ($func == "showtype") : echo "<table>";
//判断分类的状态
if ($uid != 0) {
    $result = mysql_query("select * from type where id=$uid");
    $type = mysql_result($result, 0, "type");
} else {
    $type = "父分类";
}
echo "<tr><td><a href="$php_self ? func = createtype & uid = $uid">创建分类</a></td></tr>";
echo "<tr><td>$type</td></tr>";
$result = mysql_query("select * from type where uid=$uid");
$num = mysql_numrows($result);
if (!emptyempty($num)) {
    for ($i = 0; $i < $num; $i++) {
        $id = mysql_result($result, $i, "id");
        $type = mysql_result($result, $i, "type");
        echo "<tr><td>";
        echo "<a href="$php_self ? func = showtype & uid = $id">$type</a>";
        echo "</td></tr>";
    }
}
echo "</table>";
endif; /* end showtype */ . . . . . . . . . .
?>

以上的程序便完成了无限分类的基本创建,存储和显示,接着就是完善分类创建功能的各个部分了.

路径跟踪 

前面已经介绍过了分类的创建实现方法,在分类表里记载了 rout_id 和 rout_char 这两个存储分类路径的信息,在不做任何处理的情况下,程序只能够顺序下到最底层的分类而无法倒退(当然可利用浏览器的 back 键倒退,但这对程序来说是不完整的),因此必须将 rout_id 和 rout_char 的信息分解出来完成实在的路径指示.

具体的做法,假如数据库记载了这么一条分类信息:

id:4 

uid:2 

type:开发工具 

rout_id:0:1:2:4 

rout_char:系统:linux:开发工具

当程序走到分类'开发工具'上时,除了要求显示路径信息外还要求能够去到路径上的任一分类中,该怎么做能?这里就需要用到 explode() 函数了.因为 rout_id 和 rout_char 是对应关系的,所以可将它们分解:

$path=explode(":",$rout_id);  

$path_gb=explode(":",$rout_char); 

这时所有分类信息都被分解了,现在要做的就是以链接的方式还原路径信息:  

<?php
for ($i = 0;; $i++) {
    $a = $i + 1;
    echo "<a  
href=$php_self?func=showtype&uid=", $path[$a], ">", $path_gb[$i], "</a>:";
    if (emptyempty($path_gb[$i])) {
        break;
    }
}
?>

上面这段代码就实现了加链接还原路径的功能,因为实现的是无限分类,因此是没有上限的,所以在 for($i=0;;$i++) 里没有范围限制,而设置循环退出的条件是 $path_gb[$i] 中的值为空,将这段代码插入类别显示版面的程序块内就行了: 

<?php
//显示分类************************************************
if ($func == &#39;showtype&#39;) : echo "<table>";
//判断分类的状态
if ($uid != 0) {
    $result = mysql_query("select * from type where id=$uid");
    $type = mysql_result($result, 0, "type");
    //******** 新加入的代码 ***************
    $rout_id = mysql_result($result, 0, "rout_id");
    $rout_char = mysql_result($result, 0, "rout_char");
    $path = explode(":", $rout_id);
    $path_gb = explode(":", $rout_char);
    echo "<tr><td>";
    for ($i = 0;; $i++) {
        $a = $i + 1;
        echo "<a  
href=$php_self?func=showtype&uid=", $path[$a], ">", $path_gb[$i], "</a>:";
        if (emptyempty($path_gb[$i])) {
            break;
        }
    }
    echo "</td></tr>";
    //******** end ***********************
    
} else {
    $type = &#39;父分类&#39;;
}
echo "<tr><td><a href=&#39;$php_self?func=createtype&uid=$uid&#39;>创建分类</a></td></tr>";
echo "<tr><td>$type</td></tr>";
$result = mysql_query("select * from type where uid=$uid");
$num = mysql_numrows($result);
if (!emptyempty($num)) {
    for ($i = 0; $i < $num; $i++) {
        $id = mysql_result($result, $i, "id");
        $type = mysql_result($result, $i, "type");
        echo "<tr><td>";
        echo "<a href=&#39;$php_self?func=showtype&uid=$id&#39;>$type</a>";
        echo "</td></tr>";
    }
}
echo "</table>";
endif; /* end showtype */ . . . . . . . . . .
?>

完成这个功能块后,就可继续分类信息的显示实现了


教程地址:

欢迎转载!但请带上文章地址^^

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn