最近在使用遞歸函數時,遇到一個問題,先看代碼效果再分析
先給一個數組
$arr = array(
0=>array(
'cid'=>1,
'pid'=>0,
'name'=>'亞洲',
),
1=>array(
'cid'=>2,
'pid'=>0,
'name'=>'北美洲',
),
2=>array(
'cid'=>3,
'pid'=>1,
'name'=>'中國',
),
3=>array(
'cid'=>4,
'pid'=>2,
'name'=>'美國',
),
4=>array(
'cid'=>5,
'pid'=>3,
'name'=>'北京',
),
5=>array(
'cid'=>6,
'pid'=>3,
'name'=>'河北',
),
6=>array(
'cid'=>7,
'pid'=>5,
'name'=>'東城區',
),
7=>array(
'cid'=>8,
'pid'=>5,
'name'=>'海淀區',
),
8=>array(
'cid'=>9,
'pid'=>5,
'name'=>'大興區',
),
);
正確遞歸方法:
function tree($cate,$pid=0,$level=0,$html="└―"){
global $list;
foreach($cate as $v){
if($v['pid']==$pid){
$v['html'] = str_repeat($html,$level);
$list[] = $v;
tree($cate,$v['cid'],$level+1);
}
}
return $list;
}
$lists = tree($arr);
foreach($lists as $v){
echo $v['html'].$v['name'].'<br>';
}
顯示結果:
亞洲
└―中國
└―└―北京
└―└―└―東城區
└―└―└―海淀區
└―└―└―大興區
└―└―河北
北美洲
└―美國
錯誤遞歸方法:
function tree($cate,$pid=0,$level=0,$html="└―"){
global $list;
foreach($cate as $v){
if($v['pid']==$pid){
/* 問題出在下面兩行 */
$html = str_repeat($html,$level);
$v['html'] = $html;
$list[] = $v;
tree($cate,$v['cid'],$level+1);
}
}
return $list;
}
$lists = tree($arr);
foreach($lists as $v){
echo $v['html'].$v['name'].'<br>';
}
顯示結果:
亞洲
└―中國
└―└―北京
└―└―└―東城區
└―└―└―└―└―└―└―└―└―海淀區
└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―└―大興區
└―└―└―└―河北
北美洲
└―美國
個人分析:第二種錯誤情況是因爲中間使用了一個$html中轉賦值導致的。 在遍歷$arr數組過程中,如果在一個if循環過程中,由於$html賦的值在當前作用域下是一直有效的,所以有多個數據滿足$v['pid']==$pid條件時,此時$html是會被累計追加的。只有跳出一個if循環過程後,重新回到foreach循環中時,此時已跳出if中的$html的作用域,數據才被釋放,將會重新從初始值開始。
最後做了一個驗證:將if循環結構中的$html變量名換成另一個任意名稱如$htmls,確保跟遞歸函數中的$html參數不一致,這樣就不存在作用域的問題了,修改後顯示結果顯示正常。