php中foreach使用&引用后的异常处理

小云云
发布: 2018-03-16 11:40:51
原创
1745人浏览过

可能在PHP编码中使用&引用变量或者对象或者方法的人不多,但是&引用可以让你的代码变的简单而且节省资源消耗。在这篇文章中我们重点讨论的是foreach中使用&时出现的异常以及解决办法。

$exp = [
            [                'name' => 'test1',                'age' => 15,                'extension' => 'a:3:{s:4:"nose";s:4:"long";s:5:"mouth";s:3:"big";s:3:"eye";s:5:"small";}'
            ],
            [                'name' => 'test2',                'age' => 25,                'extension' => 'a:3:{s:4:"nose";s:5:"long2";s:5:"mouth";s:4:"big2";s:3:"eye";s:6:"small2";}'
            ],
            [                'name' => 'test4',                'age' => 18,                'extension' => 'a:3:{s:4:"nose";s:5:"long2";s:5:"mouth";s:4:"big2";s:3:"eye";s:6:"small2";}'
            ],
            [                'name' => 'test3',                'age' => 20,                'extension' => 'a:3:{s:4:"nose";s:5:"long3";s:5:"mouth";s:4:"big3";s:3:"eye";s:6:"small3";}'
            ],
        ];        foreach ($exp as &$v) {            $extension = @unserialize($v['extension']);            $v['nose'] = $extension['nose'] ?? "";            $v['mouth'] = $extension['mouth'] ?? "";            $v['eye'] = $extension['eye'] ?? "";
        }        $newExp = [];        foreach ($exp as $v) {            if ($v['mouth'] == "big3"){                $newExp[] = $v;
            }
        }
        dump($newExp);        exit;
登录后复制

这部分代码的功能描述如下:

1.将exp中的扩展字段混入到exp中2.如果exp中mouth为big3则赋值给新数组newExp3.输出newExp
登录后复制
从简单的表象来分析貌似以上逻辑并没有错,而且我们预测输出的结果应该为...0 => array:6 [▼    "name" => "test3"     "age" => 20     "extension" => "a:3:{s:4:"nose";s:5:"long3";s:5:"mouth";s:4:"big3";s:3:"eye";s:6:"small3";}"     "nose" => "long3"     "mouth" => "big3"     "eye" => "small3"   ]   ...   但是结果并不是我们所预测的那样,程序输出的结果为:   []   这是为什么呢,我们来逐一分析

foreach引用引发的异常

第一个foreach是以下的代码块

foreach ($exp as &$v) {     $extension = @unserialize($v['extension']);     $v['nose'] = $extension['nose'] ?? "";     $v['mouth'] = $extension['mouth'] ?? "";     $v['eye'] = $extension['eye'] ?? "";
}
登录后复制

,在该代码块中使用了&v。因为我们这一步要做的事情是处理数组本身的数据所以使用引用对于内存消耗较少。在程序执行中

v应该就是exp最后一个元素的引用。
那么当我们修改$v的值应该exp的最后一个元素会变化。而且还有一个非常重要的问题就是foreach中使用了引用后引用在foreach结束后任然是存在的。也就是在以上的foreach之外$v依旧引用exp最后一个元素

在foreach后$v是否还存在

...foreach ($exp as &$v) {    $extension = @unserialize($v['extension']);    $v['nose'] = $extension['nose'] ?? "";    $v['mouth'] = $extension['mouth'] ?? "";    $v['eye'] = $extension['eye'] ?? "";
}  
dump($v);
输出结果为:array:6 [▼  "name" => "test3"
  "age" => 20
  "extension" => "a:3:{s:4:"nose";s:5:"long3";s:5:"mouth";s:4:"big3";s:3:"eye";s:6:"small3";}"
  "nose" => "long3"
  "mouth" => "big3"
  "eye" => "small3"]
登录后复制

第二个循环分析

$newExp = []; foreach ($exp as $v) {     if ($v['mouth'] == "big3"){         $newExp[] = $v;
     }
 }
 dump($newExp);
登录后复制

在这儿我们是做了一个常规的循环来循环exp而且在该循环中我们使用的是变量并没有使用引用。差别就是$v和 &$v请仔细看。
在这个循环中其实$v依旧是exp最后一个元素的引用。那么在循环中其实每次都是奖exp当前(current)的值赋值给$v因为引用关系最终改变的是exp最后一个元素的值。那么在foreach中exp最后子元素的值一直是变的。演变过程如下:

立即学习PHP免费学习笔记(深入)”;

//为了篇幅简略表示//第一次循环exp变为:也就是第一个元素赋值给了最后一个元素[
    [        'name' => 'test1',
        ...
    ],
    [        'name' => 'test2',
        ...
    ],
    [        'name' => 'test4',
        ...
    ],
    [        'name' => 'test1',
        ...
    ],
]//第二次循环exp变为:也就是第二个元素赋值给了最后一个元素[
    [        'name' => 'test1',
        ...
    ],
    [        'name' => 'test2',
        ...
    ],
    [        'name' => 'test4',
        ...
    ],
    [        'name' => 'test2',
        ...
    ],
]//第三次循环exp变为:也就是第三个元素赋值给了最后一个元素[
    [        'name' => 'test1',
        ...
    ],
    [        'name' => 'test2',
        ...
    ],
    [        'name' => 'test4',
        ...
    ],
    [        'name' => 'test4',
        ...
    ],
]//第四次循环exp变为:也就是第四个元素赋值给了最后一个元素 循环完毕[
    [        'name' => 'test1',
        ...
    ],
    [        'name' => 'test2',
        ...
    ],
    [        'name' => 'test4',
        ...
    ],
    [        'name' => 'test4',
        ...
    ],
]
登录后复制

原因分析

从上可以看出虽然本来exp的最后一个元素复合if条件中的 $v['mouth'] == "big3",但是在循环最后一个元素时其本身已经变成了第三个元素,所以mouth=big3的元素不存在了。这个流程有点儿绕,多看几遍就能看得懂。当然你也可以看看PHP的zend引擎中关于foreach的实现以及查看VLD中间代码,例如简单循环的VLD

number of ops:  16compiled vars:  !0 = $arr, !1 = $key, !2 = $rowline     # *  op                           fetch          ext  return  operands---------------------------------------------------------------------------------   2     0  >   INIT_ARRAY                                       ~0      1
         1      ADD_ARRAY_ELEMENT                                ~0      2
         2      ADD_ARRAY_ELEMENT                                ~0      3
         3      ADD_ARRAY_ELEMENT                                ~0      4
         4      ADD_ARRAY_ELEMENT                                ~0      5
         5      ASSIGN                                                   !0, ~0
   4     6    > FE_RESET                                         $2      !0, ->14
         7  > > FE_FETCH                                         $3      $2, ->14
         8  >   ZEND_OP_DATA                                     ~5
         9      ASSIGN                                                   !2, $3
        10      ASSIGN                                                   !1, ~5
   5    11      ECHO                                                     !1
        12      ECHO                                                     !2
   6    13    > JMP                                                      ->7
        14  >   SWITCH_FREE                                              $2
   7    15    > RETURN                                                   1
登录后复制

以上就是php中foreach使用&引用后的异常处理的详细内容,更多请关注php中文网其它相关文章!

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号