> 백엔드 개발 > PHP 튜토리얼 > PHP에서 foreach 사용 및 참조 후 예외 처리

PHP에서 foreach 사용 및 참조 후 예외 처리

小云云
풀어 주다: 2023-03-21 15:22:01
원래의
1655명이 탐색했습니다.

可能在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最后子元素的值一直是变的。演变过程如下

//为了篇幅简略表示//第一次循环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.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿