當前位置:首頁 > PHP教程 > php應用 > 列表

php無限分類代碼與原理

發布:smiling 來源: PHP粉絲網  添加日期:2013-12-23 15:32:05 瀏覽: 評論:0 

第一分類(父分類)-->第二分類(子分類)-->第三分類(孫分類),這種親緣分類越多,程序和數據庫的控制就越加的復雜困難.在同一級的分類處理和控制是非常的簡單的,因為只需要一個數據庫來記載這一級的分類就行了,如:系統,新聞等分類,在這一級上處理是很簡單的,但對一個網站來說一級分類是不夠的,還需要再分類

我們建一個表"class"

  1. CREATE TABLE `class` ( 
  2.   `id` int(11) NOT NULL auto_increment COMMENT '分類id'
  3.   `f_id` int(11) NOT NULL COMMENT '父id'
  4.   `namevarchar(25) collate gbk_bin NOT NULL COMMENT '分類名稱'
  5.   PRIMARY KEY  (`id`) 
  6. ) ENGINE=MyISAM  DEFAULT CHARSET=gbk COLLATE=gbk_bin AUTO_INCREMENT=1 ; 

首先我們往數據庫里插入‘新聞’這個大分類,因為‘新聞’是最大分類,上面沒有父類了,所以我把它的f_id設置為0。

  1. INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(1, 0, '新聞');   //id這個字段是自動增長的,可以不寫值 

然后我們再往數據庫里插入‘PHP新聞’這個分類,它的父類‘新聞’的id是1,所以它的f_id設置為1。

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

然后我們再往數據庫里插入‘PHP6.0出來了’這個分類,它的父類‘PHP新聞’的id是2,所以它的f_id設置為2。

  1. INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(3, 2, 'PHP6.0出來了'); 

同理,我們可以這樣一直往下插入分類,也就達到了無限分類,我們可以發現插入一個分類的原則關鍵是找到這個分類的父類的id,然后作為這個分類的f_id字段的值。

假設要插入跟‘新聞’同一個級別的分類‘技術’,也就是說它也是最大分類,上面沒有父類了,那么它的f_id也設置為0;

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

在‘技術’下面又有一個分類‘PHP技術’,那么我們怎么插入呢,首先找到‘PHP技術’的父類‘技術’的id,然后作為自己的f_id字段的值。

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

看到這里,想必大家應該都明白怎么往數據庫里插入各個分類了,就不再舉例了,我們已經知道如何往數據庫里插入各個分類了,那又如何把各個分類羅列出來呢?

 
  1. header("Content-type:text/html;charset=utf-8");  
  2. $db=new mysqli("localhost","root","","news_php100") ; //實例化一個數據庫連接。使用這個前一定要確保已經加載了mysqli類庫,或者用mysql_connect這個方式連接。  
  3. if(mysqli_connect_errno()){ 
  4.   echo "鏈接失敗:".mysqli_connect_error(); 
  5.   exit(); }  
  6. $db->query("set names utf8"); 
  7. $result=$db->query("select name from class where f_id=0"); //查找f_id=0的分類,也就是查找每一個大類。 
  8. while($row=$result->fetch_assoc()){ 
  9.       echo $row['name']."<br>";        //這樣就把每個大類循環出來了。 
  10. //同樣我們可以把新聞的子類循環出來。 
  11. $result=$db->query("select * from class where f_id=1"); //查找f_id=1的分類,也就是查找‘新聞’的子類。 
  12. while($row=$result->fetch_assoc()){ 
  13.       echo $row['name']." 
  14. ";        //這樣就把‘新聞’的子類循環出來了。注意:只是子類,不包括孫子類。 

寫到這里,我們會發現一個問題,如果這個分類是10級分類,難道我們要寫10個循環把它每個子類循環出來?如果是更多級分類呢,這樣寫顯然是不現實的。

那又有什么辦法解決呢?我們可以寫一個遞歸的函數,把f_id作為參數傳入,不斷循環每一個f_id的值,也就是說把每一個f_id值的子類循環出來。

首先我們把各個分類的值保存在一個二維數組中,在下面的遞歸函數里有用。

  1. $result=$db->query("select * from class"); 
  2. while($row=$result->fetch_assoc()){ 
  3.      $arr[]=array($row[id],$row[f_id],$row[name]);    //每一行保存一個分類的id,f_id,name的信息。 
  4. function fenlei($f_id=0){     //$f_id初始化為0,也就是從最大分類開始循環. 
  5.     global $arr;   //聲明$arr為全局變量才可在函數里引用。 
  6.     for($i=0;$i<count($arr);$i++){       //對每個分類進行循環。 
  7.            if($arr[$i][1]==$f_id){         //$arr[$i][1]表示第$i+1個分類的f_id的值。開始$f_id=0,也就是把f_id=0的分類輸出來。 
  8.                  echo $arr[$i][2]."<br>"//$arr[$i][1]表示第$i+1個分類的name的值。 
  9.             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,下面來看看代碼:

  1. <?  
  2. .....  
  3. ..... 
  4. //設置默認頁  
  5. if (emptyempty($func)) $func=="showtype"
  6. //設置父分類的 uid  
  7. if (emptyempty($uid)) $uid=0; 
  8. //數據庫存儲************************************************  
  9. if ($func=="save"): 
  10. $fields = "";  
  11. $values = ""
  12. if ($id!="") {  
  13. $fields .= ",id";  
  14. $values.=",$id";  
  15. if ($uid!="") {  
  16. $fields .= ",uid";  
  17. $values.=",$uid";  
  18. if ($type!="") {  
  19. $fields .= ",type";  
  20. $values.=","$type"";  
  21. if ($route_id=="") { 
  22. //取得父分類的 route_id  
  23. if ($uid!=0) {  
  24. $result = mysqlquery("select * from type where id=$uid");  
  25. $route_id=mysql_result($result,0,"route_id");  
  26. else {  
  27. $routr_id="0";  
  28. }  
  29. $fields .= ",route_id";  
  30. //形成自己的 route_id  
  31. $route_id="$route_id:$id";  
  32. $values.=","$route_id"";  
  33. //形成自己的 route_char  
  34. if ($route_char!="") {  
  35. $fields .= ",route_char";  
  36. $route_char="$route_char:$type";  
  37. $values.=","$route_char"";  
  38. else {  
  39. $fields .= ",route_char";  
  40. $route_char=$type;  
  41. $values.=","$route_char"";  
  42. $fields = substr($fields,1,strlen($fields)-1);  
  43. $values = substr($values,1,strlen($values)-1); 
  44. $result = mysqlquery("insert into type ($fields) values ($values)");  
  45. ...  
  46. endif/* end save */ 
  47.  
  48. //分類上傳************************************************  
  49. if ($func=="createtype"): 
  50. //取得自己的 id  
  51. $result = mysqlquery("select * from type order by  
  52. id desc");  
  53. $num=mysql_numrows($result);  
  54. if (!emptyempty($num)) {  
  55. $cat = mysql_result($result,0,"id");  
  56. else {  
  57. $cat=0;  
  58. //判斷分類的狀態  
  59. if ($uid != 0) {  
  60. $result=mysql_query("select * from type where id=$uid");  
  61. $type=mysql_result($result,0,"type");  
  62. $route_char=mysql_result($result,0,"route_char");  
  63. else {  
  64. $type="父分類";  
  65. }  
  66. echo "<FORM ACTION="$PHP_SELF?func=save" METHOD=POST>"
  67. echo "<table>";  
  68. echo "<tr><td>所屬類別:$type</td></tr>";  
  69. echo "<tr><td>創建分類:<input type=text name="type" SIZE=10 MAXLENGTH=100></td></tr>"
  70. echo "<tr><td>";  
  71. $cat=$cat+1;  
  72. echo "<input type=hidden name=id value="$cat">";  
  73. echo "<input type=hidden name=uid value="$uid">";  
  74. echo "<input type=hidden name=route_char value="$route_char">";  
  75. echo "<INPUT TYPE=submit NAME="Save" VALUE="保存"></td></tr>"
  76. echo "</table>";  
  77. echo "</form>";  
  78. endif/* end createtype */ 
  79. //顯示分類************************************************  
  80. if ($func=="showtype"): 
  81. echo "<table>"
  82. //判斷分類的狀態  
  83. if ($uid!=0) {  
  84. $result=mysql_query("select * from type where id=$uid");  
  85. $type=mysql_result($result,0,"type");  
  86. else {  
  87. $type="父分類";  
  88. echo "<tr><td><a href="$php_self?func=createtype&uid=$uid">創建分類</a></td></tr>"
  89. echo "<tr><td>$type</td></tr>"
  90. $result=mysql_query("select * from type where uid=$uid");  
  91. $num=mysql_numrows($result); 
  92. if (!emptyempty($num)) {  
  93. for ($i=0;$i<$num;$i++) { 
  94. $id=mysql_result($result,$i,"id");  
  95. $type=mysql_result($result,$i,"type"); 
  96. echo "<tr><td>";  
  97. echo "<a href="$php_self?func=showtype&uid=$id">$type</a>";  
  98. echo "</td></tr>";  
  99. }  
  100. echo "</table>";  
  101. endif/* end showtype */  
  102. .....  
  103. ..... 
  104. ?> 

以上的程序便完成了無限分類的基本創建,存儲和顯示,接著就是完善分類創建功能的各個部分了.

路徑跟蹤 

前面已經介紹過了分類的創建實現方法,在分類表里記載了 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 是對應關系的,所以可將它們分解:

  1. $path=explode(":",$rout_id);  
  2. $path_gb=explode(":",$rout_char); 
  3. 這時所有分類信息都被分解了,現在要做的就是以鏈接的方式還原路徑信息:  
  4. for ($i=0;;$i++) {  
  5. $a=$i+1;  
  6. echo "<a  
  7. href=$php_self?func=showtype&uid=",$path[$a],">",$path_gb[$i],"</a>:";  
  8. if (emptyempty($path_gb[$i])) {  
  9. break;  
  10. }  
  11. }  

上面這段代碼就實現了加鏈接還原路徑的功能,因為實現的是無限分類,因此是沒有上限的,所以在 for($i=0;;$i++) 里沒有范圍限制,而設置循環退出的條件是 $path_gb[$i] 中的值為空,將這段代碼插入類別顯示版面的程序塊內就行了: 

  1. //顯示分類************************************************  
  2. if ($func=='showtype'): 
  3. echo "<table>"
  4. //判斷分類的狀態  
  5. if ($uid!=0) {  
  6. $result=mysql_query("select * from type where id=$uid");  
  7. $type=mysql_result($result,0,"type"); 
  8. //******** 新加入的代碼 ***************  
  9. $rout_id=mysql_result($result,0,"rout_id");  
  10. $rout_char=mysql_result($result,0,"rout_char");  
  11. $path=explode(":",$rout_id);  
  12. $path_gb=explode(":",$rout_char);  
  13. echo "<tr><td>";  
  14. for ($i=0;;$i++) {  
  15. $a=$i+1;  
  16. echo "<a  
  17. href=$php_self?func=showtype&uid=",$path[$a],">",$path_gb[$i],"</a>:";  
  18. if (emptyempty($path_gb[$i])) {  
  19. break;  
  20. }  
  21. }  
  22. echo "</td></tr>";  
  23. //******** end *********************** 
  24. else {  
  25. $type='父分類';  
  26. echo "<tr><td><a href='$php_self?func=createtype&uid=$uid'>創建分類</a></td></tr>"
  27. echo "<tr><td>$type</td></tr>"
  28. $result=mysql_query("select * from type where uid=$uid");  
  29. $num=mysql_numrows($result); 
  30. if (!emptyempty($num)) {  
  31. for ($i=0;$i<$num;$i++) { 
  32. $id=mysql_result($result,$i,"id");  
  33. $type=mysql_result($result,$i,"type"); 
  34. echo "<tr><td>";  
  35. echo "<a href='$php_self?func=showtype&uid=$id'>$type</a>";  
  36. echo "</td></tr>";  
  37. }  
  38. echo "</table>";  
  39. endif; /* end showtype */  
  40. .....  
  41. .....  

完成這個功能塊后,就可繼續分類信息的顯示實現了

Tags: 無限 分類 代碼

分享到:

天气网首页彩吧