免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4092 | 回复: 12
打印 上一主题 下一主题

发现php的一个BUG.其实都好几年了.有人说是trick(陷阱) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-10-08 11:42 |只看该作者 |倒序浏览
这个bug是:
Foreach by reference bug
我今天偶然发现的,汗的是,查看手册发现早就有人提出这BUG,而且到网上一搜发现此BUG的历史还很悠久,可以追溯到2000年的php4.
bug相关链接:
http://bugs.php.net/bug.php?id=29992
http://bugs.php.net/bug.php?id=8373
测试代码:
$a=array('a','b');
foreach($a as &$v){
}
foreach($a as $v){
    echo $v;
}


这个BUG真是奇
怪了.
ps:
有人说是trick(陷阱).貌似还是php官方推荐的使用习惯
真是自圆其说呀!
psps:
有搜了一下,原来php团队早就知道这个,但就是不认为是bug.不知道底层的原因是什么,难道和内部机制有关?当是php专有特性吧.小心就是了.


[ 本帖最后由 achun.shx 于 2008-10-8 12:08 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-10-08 12:33 |只看该作者
“貌似还是php官方推荐的使用习惯”
这个怎么用?

论坛徽章:
0
3 [报告]
发表于 2008-10-08 12:38 |只看该作者
关键是循环引用后一定要有注销引用的好习惯
比如

  1. $a=array('a','b');
  2. foreach($a as &$v){
  3. }
  4. //unset($v);
  5. $v='c';
  6. print_r($a);
复制代码

这就出问题了



  1. $a=array('a','b');
  2. foreach($a as &$v){
  3. }
  4. unset($v);//注销引用后这就不是问题的问题
  5. foreach($a as $v){
  6.     echo $v;
  7. }
复制代码

论坛徽章:
0
4 [报告]
发表于 2008-10-08 12:57 |只看该作者
$a=array('a','b');
foreach($a as &$v){     

}

foreach ($a as $v) {
        echo $v;
}
print_r($a);    //最后添加这句你会看到 结果的 数组 $a已经被改变了。

第一个循环结束后 $v是个指向数组$a[1] 的 也就是 ‘b’的位置。
当第二个循环开始后 $a as $v第一次执行就是 把 $a 的第一个元素 'a'拷贝给 $v,相当于$v = $a[0] ,所以 $v 就变成了‘a’ ,你忘了在第一个循环结束时候的$v还是指向$a[1]的引用呢,所以成了$a[1] = $a[0],$a就被改变了。$a[1] 被改成 ‘a’ 就成你你看到的接过。

[ 本帖最后由 shitou254 于 2008-10-8 13:00 编辑 ]

论坛徽章:
0
5 [报告]
发表于 2008-10-08 16:19 |只看该作者
领教了。

论坛徽章:
0
6 [报告]
发表于 2008-10-08 17:42 |只看该作者
那个不是bug,php的foreach就有这个用法
foreach ($arr as &$v) {
  $v='another value';
}

foreach ($arr as $key=>$v) {
  $arr[$key] = 'another value';
}
哪种简单?

论坛徽章:
0
7 [报告]
发表于 2008-10-17 13:44 |只看该作者

症状对,但楼上解释的不对

<pre>
<?
$ar = array ( 1,2,3,4);

foreach ($ar as &$item)
{
        print_r($item);
}
foreach ($ar as $item)
{
        print_r($item);
}
print_r($ar);
?>

如果按照楼上的解释,应该打印
1231才对。但实际上打印的是1233

手册里建议在foreach之后unset($item),确实可以工作。
但这个问题的症状很有趣

论坛徽章:
0
8 [报告]
发表于 2008-10-20 23:33 |只看该作者
不是bug,针对这个
《php5 Power Programming》
中文《 php5权威编程》 P26有很详细的描述:
foreach($array as [$key =>] [&] $value)

设置&在值前面也是可选的,在你想更改$value的值,并在$array中也生效的时候,你就需要它。


虽然不是指针,但有这个味道。可以理解 引用传递。

6楼 并没有错,只是给你个实例看看,虽然不一定要这么用。

[ 本帖最后由 lendy 于 2008-10-20 23:40 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2008-10-21 00:05 |只看该作者
关于
<?
$ar = array ( 1,2,3,4);

foreach ($ar as &$item)
{
        print_r($item);
}
//step 1
foreach ($ar as $item)
{
//step 2
        print_r($item);
}
print_r($ar);
?>
的理解:
step 1
$item 应该指向 $ar[3]
然后的循环一直是没变过。
第一次step 2循环,把 $ar[0] 赋值给 $item ,这里 $item 是指向 $ar[3]的,所以$ar[3]=1
第二次step 2循环,把 $ar[1] 赋值给 $item ,这里 $item 是指向 $ar[3]的,所以$ar[3]=2
。。。
第四次的时候
把 $ar[3] 赋值给 $item ,把 $ar[3]在第三次的时候不是已经是3了啊,那不是自己在修改自己,还是3
你可以试试这个

<?php

$ar = array ( 1,2,3,4);

foreach ($ar as &$item)
{
        print_r($item);
        
}

foreach ($ar as $item)
{
        print_r($item);
        break;
}
print_r($ar);
?>

看看是不是1231


你也可以试试step 2的2次循环是不是1232

我觉得你应该好好看看c的指针。

[ 本帖最后由 lendy 于 2008-10-21 00:14 编辑 ]

论坛徽章:
0
10 [报告]
发表于 2008-10-21 00:12 |只看该作者
然后看看这个:

<?php

$ar = array ( 1,2,3,4);

foreach ($ar as &$item)
{
        print_r($item);
        break;
}

foreach ($ar as $item)
{
//step 2
        print_r($item); //r1
        
}
print_r($ar); //r2


?>

r1 和 r2打出来的东西不一样
是在step 2 的第四次循环后才把 $ar[0] 的值给修改了,因为 $item 指向 $ar[0]。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP