工作中总会遇到一些奇奇怪怪的由前人所写下的不可置疑的代码,如果你仅仅跟着眼前所见的代码去理解他人的思路,Well You have fell into a terrible situation.
贴一段示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?php $students = [ ['name'=>'Jackson','age'=>15], ['name'=>'Jerry','age'=>14], ['name'=>'Amy','age'=>14] ]; $classes = [ 'CL001'=>['name'=>'Language','classTime'=>30], 'CL002'=>['name'=>'PE','classTime'=>13] ];
foreach ($students as $k=>&$v){ $v['name-age'] = $v['name'] . '-' .$v['age']; }
$classString = '';
foreach ($classes as $k=>$v){ $classString .= 'ClassID:'.$k.'-'.$v['name'].PHP_EOL; } echo $classString; var_dump($students);
|
你也许会回答这样一个输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| ClassID:CL001-Language ClassID:CL002-PE array(3) { [0]=> array(3) { ["name"]=> string(7) "Jackson" ["age"]=> int(15) ["name-age"]=> string(10) "Jackson-15" } [1]=> array(3) { ["name"]=> string(5) "Jerry" ["age"]=> int(14) ["name-age"]=> string(8) "Jerry-14" } [2]=> array(3) { ["name"]=> string(3) "Amy" ["age"]=> int(14) ["name-age"]=> string(6) "Amy-14" } }
|
也许会有不少人会使用foreach+引用符号’&’来遍历更新数组内容,这样也的确可行。但是!这里就惊现了这样一个巨坑,为何在循环$classes之后,$students变得面目全非?来看看实际输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ClassID:CL001-Language ClassID:CL002-PE array(3) { [0]=> array(3) { ["name"]=> string(7) "Jackson" ["age"]=> int(15) ["name-age"]=> string(10) "Jackson-15" } [1]=> array(3) { ["name"]=> string(5) "Jerry" ["age"]=> int(14) ["name-age"]=> string(8) "Jerry-14" } [2]=> &array(2) { ["name"]=> string(2) "PE" ["classTime"]=> int(13) } }
|
发现了吧,最后一项为什么是$classes的元素?而且是其最后一项?聪明的你现在应该在开始思考’&’符号了!
两次foreach循环我们都用了$k和$v来代替键和值,但在&符号作用在$v上的时候,这个$v实际是每次循环的元素地址。而在第二个foreach中使用的$v实际上已经是一个存在的引用(指向上一个数组的最后一次访问的元素),在对他进行赋值修改时,就会导致与其实际指向的数据发生修改,因为他们就是逻辑上的“相同内存”。
我所举例的代码比较容易发现问题,其实我实际遇到的问题却糟糕的多,因为第二次循环是为了给第一次循环的内容进行填补,所以元素结构是一模一样的,这样出现的现象就是同一个元素在数组中出现了两次,其中原数组的最后一个元素指向第二次循环的数组的最后一个。
这里举例的是当&符号用在=>后面的值变量,如果用在=>前面的键变量呢???
实在可怕! 还好我喜欢用array_walk来代替此类做法。