PHP Foreach Pass by Reference : 마지막 요소 복제? (곤충?)
방금 작성한 간단한 PHP 스크립트로 매우 이상한 행동을했습니다. 버그를 다시 만드는 데 필요한 최소한으로 줄였습니다.
<?php
$arr = array("foo",
"bar",
"baz");
foreach ($arr as &$item) { /* do nothing by reference */ }
print_r($arr);
foreach ($arr as $item) { /* do nothing by value */ }
print_r($arr); // $arr has changed....why?
?>
이 결과는 다음과 같습니다.
Array
(
[0] => foo
[1] => bar
[2] => baz
)
Array
(
[0] => foo
[1] => bar
[2] => bar
)
이것이 버그입니까 아니면 이상한 행동일까요?
첫 번째 foreach 루프 $item
후에도 여전히 사용중인 일부 값에 대한 참조 $arr[2]
입니다. 따라서 참조로 호출하지 않는 두 번째 루프의 각 foreach 호출은 해당 값을 $arr[2]
새 값으로 바꿉니다 .
따라서 루프 1, 값 $arr[2]
이되고 $arr[0]
'foo'가됩니다.
루프 2, 값 $arr[2]
이되고 $arr[1]
'bar'가됩니다.
루프 3의 값 $arr[2]
이 될 $arr[2]
'바'(인해 루프 2)이다.
'baz'값은 실제로 두 번째 foreach 루프의 첫 번째 호출에서 손실됩니다.
출력 디버깅
루프가 반복 될 때마다 $item
배열 의 값을 재귀 적으로 인쇄 할뿐만 아니라 값을 에코합니다 $arr
.
첫 번째 루프가 실행되면 다음과 같은 출력이 나타납니다.
foo
Array ( [0] => foo [1] => bar [2] => baz )
bar
Array ( [0] => foo [1] => bar [2] => baz )
baz
Array ( [0] => foo [1] => bar [2] => baz )
루프의 끝에서 $item
여전히 같은 위치를 가리키고 $arr[2]
있습니다.
두 번째 루프가 실행되면 다음과 같은 출력이 나타납니다.
foo
Array ( [0] => foo [1] => bar [2] => foo )
bar
Array ( [0] => foo [1] => bar [2] => bar )
bar
Array ( [0] => foo [1] => bar [2] => bar )
각 배열이 새로운 값을 넣는 방법을 알 수 있습니다. 둘 다 여전히 동일한 위치를 가리 키기 때문에 동일한 값으로 $item
업데이트 $arr[3]
됩니다. 루프가 배열의 세 번째 값에 도달하면 해당 루프 bar
의 이전 반복에 의해 설정 되었기 때문에 값이 포함됩니다 .
버그입니까?
No. This is the behavior of a referenced item, and not a bug. It would be similar to running something like:
for ($i = 0; $i < count($arr); $i++) { $item = $arr[$i]; }
A foreach loop isn't special in nature in which it can ignore referenced items. It's simply setting that variable to the new value each time like you would outside of a loop.
$item
is a reference to $arr[2]
and is being overwritten by the second foreach loop as animuson pointed out.
foreach ($arr as &$item) { /* do nothing by reference */ }
print_r($arr);
unset($item); // This will fix the issue.
foreach ($arr as $item) { /* do nothing by value */ }
print_r($arr); // $arr has changed....why?
While this may not officially be a bug, in my opinion it is. I think that the problem here is we have the expectation for $item
to go out of scope when the loop is exited as it would in a lot of other programming languages. However that doesn't seem to be the case...
This code...
$arr = array('one', 'two', 'three');
foreach($arr as $item){
echo "$item\n";
}
echo $item;
Gives the output...
one
two
three
three
As other people already said, you're overwriting the referenced variable in $arr[2]
with your second loop, but it's only happening because $item
never went out of scope. What do you guys think... bug?
An easier explanation, seems from Rasmus Lerdorf, original creator of PHP: https://bugs.php.net/bug.php?id=71454
The correct behaviour of PHP sould be a NOTICE error in my oppinion. If a referenced variable created in a foreach loop is used outside the loop it should cause a notice. Very easy to fall for this behaviour, very difficult to spot it when it happened. And no developer is going to read the foreach documentation page, it's not a help.
You should unset()
the reference after your loop to avoid this sort of issue. unset() on a reference will just remove the reference without harming the original data.
that's because you use by ref directive (&). last value will be replace by the second loop and it corrupt your array. the simplest solution is to use different name for second loop:
foreach ($arr as &$item) { ... }
foreach ($arr as $anotherItem) { ... }
'IT story' 카테고리의 다른 글
어느 것이 더 맞습니까? (0) | 2020.06.07 |
---|---|
자바 스크립트 null 확인 (0) | 2020.06.07 |
src 및 dist 폴더의 역할은 무엇입니까? (0) | 2020.06.07 |
어설 션은 언제 프로덕션 코드에 있어야합니까? (0) | 2020.06.07 |
py 스크립트에서 sys.setdefaultencoding (“utf-8”)을 사용해서는 안되는 이유는 무엇입니까? (0) | 2020.06.07 |