這篇文章分為兩種情況,介紹了在遞歸和不使用遞歸的情況下PHP實現無限級分類,PHP無限分類在我們的開發過程中是非常長見到的,我們今後的開發中也會很常的使用到PHP無限分類,那麼我們就更應該掌握它了,不太了解PHP如何實現無限分類的小伙伴們可以參考一下本篇文章
做PHP這麼長時間,發現後台管理系統不可少的一個應用模組就是對欄目的分類,一般情況下欄目都要做成是無限級的,也就是說每個專欄理論上都可以添加子欄。在我看來這種情況處理起來整體上說也不是很複雜,唯一一個相對來說較難的點是無限級欄目的查詢。
下面就這種情況我來向大家做一個簡單的介紹,對於這種無限級欄目的查詢一般情況下有兩種方式,其中一種就是使用棧的機制,另一種是使用遞歸函數的方式(當然遞歸函數實作機制也是藉助於堆疊來實現的)。就這兩種方式下面我們分別介紹。
遞迴函數實作方式
上面提到,遞迴函數的也是藉助於堆疊的機制實現的,但是底層對於堆疊的處理對於程式設計師來說都是透明的,程式設計師只需要關心應用的實作邏輯。所以說使用遞歸處理上述問題理解起來比較容易,程式碼也比較簡潔。
既然使用遞歸函數,看名字我們就知道必須藉助於自訂的函數。我先大概說一下其實現思路,具體細節我們反映在程式碼中。
對於每一層的函數其主要做的工作就是查找父Id為當前Id的欄目,查找到以後再次調用自身函數,將查找到的欄目的id作為下一層的父id。
其流程圖如下
圖一
#不知道對於上面的解釋大家能不能理解,沒關係我們下面直接看程式碼
<?php $channels = array( array('id'=>1,'name'=>"衣服",'parId'=>0), array('id'=>2,'name'=>"书籍",'parId'=>0), array('id'=>3,'name'=>"T恤",'parId'=>1), array('id'=>4,'name'=>"裤子",'parId'=>1), array('id'=>5,'name'=>"鞋子",'parId'=>1), array('id'=>6,'name'=>"皮鞋",'parId'=>5), array('id'=>7,'name'=>"运动鞋",'parId'=>5), array('id'=>8,'name'=>"耐克",'parId'=>7), array('id'=>9,'name'=>"耐克",'parId'=>3), array('id'=>10,'name'=>"鸿星尔克",'parId'=>7), array('id'=>11,'name'=>"小说",'parId'=>2), array('id'=>12,'name'=>"科幻小说",'parId'=>11), array('id'=>13,'name'=>"古典名著",'parId'=>11), array('id'=>14,'name'=>"文学",'parId'=>2), array('id'=>15,'name'=>"四书五经",'parId'=>14) ); $html = array(); /** * 递归查找父id为$parid的结点 * @param array $html 按照父-》子的结构存放查找出来的结点 * @param int $parid 指定的父id * @param array $channels 数据数组 * @param int $dep 遍历的深度,初始化为1 */ function getChild(&$html,$parid,$channels,$dep){ /* * 遍历数据,查找parId为参数$parid指定的id */ for($i = 0;$i<count($channels);$i++){ if($channels[$i]['parId'] == $parid){ $html[] = array('id'=>$channels[$i]['id'],'name'=>$channels[$i]['name'],'dep'=>$dep); getChild($html,$channels[$i]['id'],$channels,$dep+1); } } } getChild($html,0,$channels,1); ?>
這是遞歸實現無限級欄位查詢的核心程式碼,結合圖一對其實作流程應該有一個較清晰的認知。
非遞歸,即使用堆疊機制實現無限級欄目的查詢
#在上面我們大概介紹了一下使用遞歸的方式實現無限級欄目的查詢,下面我們簡單介紹一下非遞歸的方式。雖然不用遞歸函數的方式,但是鑑於無限級欄目的結構頁需要參考遞歸的實作機制-棧的機制,解決這個問題。
在上學的時候老師就說,其實棧的核心機制也就四個字:先進後出。
在這對堆疊的機制不多說,主要說一下如何借助堆疊實作無限層級欄位查詢。
1. 先將頂層欄位壓入堆疊中
#2. 將堆疊頂元素出堆疊
3. 將出棧元素存入數組中,標記其深度(其深度就是在其父欄目的深度上面加1)
##4. 以出棧的元素為父欄目,找出其子欄位
5. 將查找到的子欄位入棧,重複步驟2
6.判斷棧為空的話,流程結束;
透過上述步驟的翻譯,可以將這些步驟翻譯成PHP程式碼,其核心程式碼如下
<?php $channels = array( array('id'=>1,'name'=>"衣服",'parId'=>0), array('id'=>2,'name'=>"书籍",'parId'=>0), array('id'=>3,'name'=>"T恤",'parId'=>1), array('id'=>4,'name'=>"裤子",'parId'=>1), array('id'=>5,'name'=>"鞋子",'parId'=>1), array('id'=>6,'name'=>"皮鞋",'parId'=>5), array('id'=>7,'name'=>"运动鞋",'parId'=>5), array('id'=>8,'name'=>"耐克",'parId'=>7), array('id'=>9,'name'=>"耐克",'parId'=>3), array('id'=>10,'name'=>"鸿星尔克",'parId'=>7), array('id'=>11,'name'=>"小说",'parId'=>2), array('id'=>12,'name'=>"科幻小说",'parId'=>11), array('id'=>13,'name'=>"古典名著",'parId'=>11), array('id'=>14,'name'=>"文学",'parId'=>2), array('id'=>15,'name'=>"四书五经",'parId'=>14) ); $stack = array(); //定义一个空栈 $html = array(); //用来保存各个栏目之间的关系以及该栏目的深度 /* * 自定义入栈函数 */ function pushStack(&$stack,$channel,$dep){ array_push($stack, array('channel'=>$channel,'dep'=>$dep)); } /* * 自定义出栈函数 */ function popStack(&$stack){ return array_pop($stack); } /* * 首先将顶级栏目压入栈中 */ foreach($channels as $key=>$val){ if($val['parId'] == 0) pushStack($stack,$val,0); } /* * 将栈中的元素出栈,查找其子栏目 */ do{ $par = popStack($stack); //将栈顶元素出栈 /* * 查找以此栏目为父级栏目的id,将这些栏目入栈 */ for($i=0;$i<count($channels);$i++){ if($channels[$i]['parId'] == $par['channel']['id']){ pushStack($stack,$channels[$i],$par['dep']+1); } } /* * 将出栈的栏目以及该栏目的深度保存到数组中 */ $html[] = array('id'=>$par['channel']['id'],'name'=>$par['channel']['name'],'dep'=>$par['dep']); }while(count($stack)>0);上面就是使用非遞歸方式實現的。 下載程式碼:
https://github.com/onmpw/phpApp
#總結上面兩種方式各有利弊,雖然實作形式上面不同,但是鑑於無限級欄目的結構,二者實現的機制都是相同的──都藉助堆疊的方式來實現。在現實情況中,我們要根據現實情況的需要選擇一種方式來實現。推薦文章:
以上是PHP實作無限分類的兩種方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!