php無限分類代碼與原理
來源:程序員人生 發布時間:2014-04-07 17:57:33 閱讀次數:2638次
第一分類(父分類)-->第二分類(子分類)-->第三分類(孫分類),這種親緣分類越多,程序和數據庫的控制就越加的復雜困難.在同一級的分類處理和控制是非常的簡單的,因為只需要一個數據庫來記載這一級的分類就行了,如:系統,新聞等分類,在這一級上處理是很簡單的,但對一個網站來說一級分類是不夠的,還需要再分類
我們建一個表"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, 'PHP6.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技術');
看到這里,想必大家應該都明白怎么往數據庫里插入各個分類了,就不再舉例了,我們已經知道如何往數據庫里插入各個分類了,那又如何把各個分類羅列出來呢?
- header("Content-type:text/html;charset=utf-8");
- $db=new mysqli("localhost","root","","news_php100") ;
- 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");
- while($row=$result->fetch_assoc()){
- echo $row['name']."<br>";
- }
-
- $result=$db->query("select * from class where f_id=1");
- while($row=$result->fetch_assoc()){
- echo $row['name']."
- ";
- }
寫到這里,我們會發現一個問題,如果這個分類是10級分類,難道我們要寫10個循環把它每個子類循環出來?如果是更多級分類呢,這樣寫顯然是不現實的。
那又有什么辦法解決呢?我們可以寫一個遞歸的函數,把f_id作為參數傳入,不斷循環每一個f_id的值,也就是說把每一個f_id值的子類循環出來。
首先我們把各個分類的值保存在一個二維數組中,在下面的遞歸函數里有用。
- $result=$db->query("select * from class");
- while($row=$result->fetch_assoc()){
- $arr[]=array($row[id],$row[f_id],$row[name]);
- }
- function fenlei($f_id=0){
- global $arr;
- for($i=0;$i<count($arr);$i++){
- if($arr[$i][1]==$f_id){
- echo $arr[$i][2]."<br>";
- fenlei($arr[$i][0]);
- }
- }
- }
在介紹這個功能前,先介紹一下 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,下面來看看代碼:
- <?
- .....
- .....
-
- if (emptyempty($func)) $func=="showtype";
-
- 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=="") {
-
- 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:$id";
- $values.=","$route_id"";
- }
-
- 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;
-
-
- if ($func=="createtype"):
-
- $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;
-
- 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;
- .....
- .....
- ?>
以上的程序便完成了無限分類的基本創建,存儲和顯示,接著就是完善分類創建功能的各個部分了.
路徑跟蹤
前面已經介紹過了分類的創建實現方法,在分類表里記載了 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);
- 這時所有分類信息都被分解了,現在要做的就是以鏈接的方式還原路徑信息:
- 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] 中的值為空,將這段代碼插入類別顯示版面的程序塊內就行了:
-
- if ($func=='showtype'):
- 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>";
-
- } 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 */
- .....
- .....
完成這個功能塊后,就可繼續分類信息的顯示實現了
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈