最近在使用递归函数时,遇到一个问题,先看代码效果再分析
先给一个数组
$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参数不一致,这样就不存在作用域的问题了,修改后显示结果显示正常。