php實(shí)現(xiàn)無(wú)限級(jí)分類(lèi)(遞歸方法)
相信很多學(xué)php的很多小伙伴都會(huì)嘗試做一個(gè)網(wǎng)上商城作為提升自己技術(shù)的一種途徑。各種對(duì)商品分類(lèi),商品名之類(lèi)的操作應(yīng)該是得心應(yīng)手,那么就可以嘗試下無(wú)限級(jí)分類(lèi)列表的制作了。
到網(wǎng)上一搜php無(wú)限極分類(lèi),很多,但好多都是一個(gè),并且,寫(xiě)的很亂,代碼很多,讓我們?cè)趺磳W(xué)習(xí)嘛,那些都不靠譜,還是自己搗鼓搗鼓無(wú)限極分類(lèi)了。
什么是無(wú)限級(jí)分類(lèi)?
無(wú)限級(jí)分類(lèi)是一種分類(lèi)技巧,例如部門(mén)組織,文章分類(lèi),學(xué)科分類(lèi)等常用到無(wú)限級(jí)分類(lèi),將其簡(jiǎn)單理解成分類(lèi)就好了。其實(shí)我們仔細(xì)想一下,生活中的分類(lèi)簡(jiǎn)直太多了,衣服可以分為男裝和女裝,也可以分為上衣和褲子,也可以根據(jù)年齡段分類(lèi)。分類(lèi)無(wú)處不在,分類(lèi)顯得“無(wú)限”。我這里就不說(shuō)無(wú)限分類(lèi)的必要性了。
無(wú)限級(jí)分類(lèi)原理簡(jiǎn)介
無(wú)限分類(lèi)看似"高大上",實(shí)際上原理是非常簡(jiǎn)單的 。無(wú)限分類(lèi)不僅僅需要代碼的巧妙性,也要依托數(shù)據(jù)庫(kù)設(shè)計(jì)的合理性。要滿(mǎn)足無(wú)限級(jí)分類(lèi),數(shù)據(jù)庫(kù)需要有兩個(gè)必須的字段,id,pid。id用來(lái)標(biāo)識(shí)自身,而pid則是用來(lái)表明父級(jí)id。也就是說(shuō),每個(gè)分類(lèi)記錄不僅描述了自身,還描述了與其關(guān)心最為緊密的另一個(gè)id??此茝?fù)雜的事情被這樣一個(gè)小技巧解決了。
閑話(huà)不多說(shuō),該展現(xiàn)本文的實(shí)例了。
作為一個(gè)狂熱海賊迷,這篇的實(shí)例我就以《海賊王》人物組織做案例。
數(shù)據(jù)庫(kù)準(zhǔn)備:
建表onepiece:
create table onepiece( id int auto_increment, pid int not null, name varchar(225) not null, primary key(id) );
插入測(cè)試數(shù)據(jù):
insert onepiece values (1,0,'海軍'), (2,0,'海賊'), (3,0,'革命軍'), (4,1,'青雉'), (5,1,'赤犬'), (6,1,'黃猿'), (7,2,'四皇'), (8,2,'七武海'), (9,2,'草帽海賊團(tuán)'), (10,9,'索隆'), (11,7,'香克斯'), (12,8,'多弗朗明哥'), (13,8,'克洛克達(dá)爾');
這里還是科普下海賊王里面的設(shè)定:世界分為三大陣營(yíng):海軍,海賊,革命軍。海軍有大將:青雉,赤犬,黃猿。海賊有:四皇,七武海,草帽海賊團(tuán)。四皇有香克斯,七武海有多弗朗明哥,克洛克達(dá)爾,草帽海賊團(tuán)有索隆。(打個(gè)廣告:海賊王真的很好看)。
最終目的:
我們今天制作的是兩種形式的無(wú)限級(jí)分類(lèi)形式,一種是下拉列表式,一種則是導(dǎo)航Link式的。直接上效果圖了:

下拉列表式

導(dǎo)航Link式
實(shí)例代碼:
我封裝了一個(gè)Unlimited類(lèi),用來(lái)調(diào)用diaplayList()展現(xiàn)下拉列表形式,調(diào)用diaplayLink展現(xiàn)導(dǎo)航Link分類(lèi)。也可以增加(addNodes())和刪除(deleteNodes)分類(lèi)。
<?php
class Unlimited{
protected $mysqli;
public function __construct($config){
$this->mysqli=new mysqli($config['host'],$config['user'],$config['pwd']);
$this->mysqli->select_db($config['db']);
$this->mysqli->set_charset('utf8');
if ($this->mysqli->connect_errno) {
echo $this->mysqli->connect_error;
}
}
private function getList($pid=0,&$result=array(),$spac=0){
$spac=$spac+2;
$sql="select * from onepiece where pid={$pid}";
$rs=$this->mysqli->query($sql);
while($row=$rs->fetch_assoc()) {
$row['name']=str_repeat('  ',$spac).$row['name'];
$result[]=$row;
$this->getList($row['id'],$result,$spac);
}
return $result;
}
/**
* 展現(xiàn)下拉列表式分類(lèi)
* @return [type]
*/
public function displayList(){
$rs=$this->getList();
$str="<select name='cate'>";
foreach ($rs as $key => $val) {
$str.="<option >{$val['name']}</option>";
}
$str.="</select>";
return $str;
}
private function getLink($cid,&$result=array()){
$sql="select * from onepiece where id={$cid}";
$rs=$this->mysqli->query($sql);
if($row=$rs->fetch_assoc()){
$result[]=$row;
$this->getLink($row['pid'],$result);
}
return array_reverse($result);
}
/**
* 展現(xiàn)導(dǎo)航Link
* @param [type] $cid [description]
* @return [type] [description]
*/
public function displayLink($cid){
$rs=$this->getLink($cid);
$str='';
foreach ($rs as $val) {
$str.="<a href=''>{$val['name']}</a>>";
}
return $str;
}
/**
* 增加分類(lèi)
* @param [type] $pid 父類(lèi)id
* @param [type] $name 本類(lèi)名
*/
public function addNodes($pid,$name){
$sql="insert into onepiece values('',{$pid},'".$name."')";
if($this->mysqli->query($sql)){
return true;
}
}
/**
* 刪除分類(lèi)
* @param [type] $id 本類(lèi)id
* @return [type]
*/
public function deleteNodes($id){
$sql="select * from onepiece where pid ={$id}";
$rs=$this->mysqli->query($sql);
if($row=$rs->fetch_assoc()){
$mes="還有子元素,請(qǐng)勿刪除";
}else{
$sql="delete from onepiece where id={$id}";
if($this->mysqli->query($sql)){
$mes="刪除成功";
}
}
return $mes;
}
}
類(lèi)中函數(shù)主要采取了遞歸函數(shù)的方法,如果理解深刻理解遞歸函數(shù),其余的部分也就水到渠成了。我會(huì)在后面的部分詳細(xì)介紹實(shí)現(xiàn)遞歸函數(shù)的三種方法。
我們?cè)賮?lái)看一個(gè)實(shí)例:
首先建立分類(lèi)信息表:
CREATE TABLE IF NOT EXISTS `category` ( `categoryId` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `parentId` smallint(5) unsigned NOT NULL DEFAULT '0', `categoryName` varchar(50) NOT NULL, PRIMARY KEY (`categoryId`) ) ;
插入若干數(shù)據(jù):
INSERT INTO `category` (`categoryId`, `parentId`, `categoryName`) VALUES (1, 0, 'php'), (2, 0, 'java'), (3, 0, 'c/c++'), (4, 1, 'php基礎(chǔ)'), (5, 1, 'php開(kāi)源資料'), (6, 1, 'php框架'), (7, 2, 'java Se'), (8, 2, 'java EE'), (9, 2, 'java Me'), (10, 3, 'c/c++基礎(chǔ)編程'), (11, 3, 'c/c++系統(tǒng)開(kāi)發(fā)'), (12, 3, 'c嵌入式編程'), (13, 3, 'c++應(yīng)用開(kāi)發(fā)'), (14, 13, 'c++桌面應(yīng)用開(kāi)發(fā)'), (15, 13, 'c++游戲開(kāi)發(fā)');
下面是php代碼:
<?php
/*
php無(wú)限極分類(lèi)
*/
//獲取某分類(lèi)的直接子分類(lèi)
function getSons($categorys,$catId=0){
$sons=array();
foreach($categorys as $item){
if($item['parentId']==$catId)
$sons[]=$item;
}
return $sons;
}
//獲取某個(gè)分類(lèi)的所有子分類(lèi)
function getSubs($categorys,$catId=0,$level=1){
$subs=array();
foreach($categorys as $item){
if($item['parentId']==$catId){
$item['level']=$level;
$subs[]=$item;
$subs=array_merge($subs,getSubs($categorys,$item['categoryId'],$level+1));
}
}
return $subs;
}
//獲取某個(gè)分類(lèi)的所有父分類(lèi)
//方法一,遞歸
function getParents($categorys,$catId){
$tree=array();
foreach($categorys as $item){
if($item['categoryId']==$catId){
if($item['parentId']>0)
$tree=array_merge($tree,getParents($categorys,$item['parentId']));
$tree[]=$item;
break;
}
}
return $tree;
}
//方法二,迭代
function getParents2($categorys,$catId){
$tree=array();
while($catId != 0){
foreach($categorys as $item){
if($item['categoryId']==$catId){
$tree[]=$item;
$catId=$item['parentId'];
break;
}
}
}
return $tree;
}
//測(cè)試 部分
$pdo=new PDO('mysql:host=localhost;dbname=test','root','8888');
$stmt=$pdo->query("select * from category order by categoryId");
$categorys=$stmt->fetchAll(PDO::FETCH_ASSOC);
$result=getSons($categorys,1);
foreach($result as $item)
echo $item['categoryName'].'<br>';
echo '<hr>';
$result=getSubs($categorys,0);
foreach($result as $item)
echo str_repeat(' ',$item['level']).$item['categoryName'].'<br>';
echo '<hr>';
$result=getParents($categorys,7);
foreach($result as $item)
echo $item['categoryName'].' >> ';
echo '<hr>';
$result=getParents2($categorys,15);
foreach($result as $item)
echo $item['categoryName'].' >> ';
?>
看下最終結(jié)果吧

雖然本文介紹的是使用遞歸來(lái)實(shí)現(xiàn)的無(wú)限級(jí)分類(lèi),但實(shí)際上,并不推薦大家這么做,大家知道分類(lèi)多了,遞歸效率也就低了,本文這里僅僅是為了讓大家更好的理解遞歸才這么做的。
- php實(shí)現(xiàn)無(wú)限級(jí)分類(lèi)查詢(xún)(遞歸、非遞歸)
- thinkphp實(shí)現(xiàn)無(wú)限分類(lèi)(使用遞歸)
- php無(wú)限極分類(lèi)遞歸排序?qū)崿F(xiàn)方法
- PHP 無(wú)限分類(lèi)三種方式 非函數(shù)的遞歸調(diào)用!
- php遞歸方法實(shí)現(xiàn)無(wú)限分類(lèi)實(shí)例代碼
- PHP實(shí)現(xiàn)遞歸無(wú)限級(jí)分類(lèi)
- php實(shí)現(xiàn)無(wú)限級(jí)分類(lèi)實(shí)現(xiàn)代碼(遞歸方法)
- php遞歸實(shí)現(xiàn)無(wú)限分類(lèi)生成下拉列表的函數(shù)
- php 無(wú)極分類(lèi)(遞歸)實(shí)現(xiàn)代碼
- php菜單/評(píng)論數(shù)據(jù)遞歸分級(jí)算法的實(shí)現(xiàn)方法
相關(guān)文章
PHP中利用substr_replace將指定兩位置之間的字符替換為*號(hào)
PHP的substr_replace將指定兩位置之間的字符替換為*號(hào)的代碼,需要的朋友可以參考下。2011-01-01
隱藏Nginx或Apache以及PHP的版本號(hào)的方法
這篇文章主要介紹了隱藏Nginx或Apache以及PHP的版本號(hào)的方法,主要用來(lái)防止針對(duì)性的漏洞攻擊,需要的朋友可以參考下2016-01-01

