이 질문에는 이미 답변이 있습니다.
다음은 간단한 루프입니다.
$list = array("A", "B", "C","D");
foreach ($list as $var) {
print(current($list));
}
출력 (데모)
BBBB // Output for 5.2.4 - 5.5.0alpha4
BCD // Output for 4.4.1
AAAA // Output for 4.3.0 - 4.4.0, 4.4.2 - 5.2.3
의문 :
foreach
나는해야한다.AAAA
하지만 현재 상황에서는 그렇지 않다.PHP
안정 버전참고 * 나는 내가 쉽게 사용할 수 있다는 것을 알고있다.print $var
하지만 from PHP DOC
current - 배열의 현재 요소를 반환합니다. 그만큼흐름()함수는 단순히 내부 포인터에 의해 가리켜지고있는 배열 요소의 값을 반환합니다. 어떤 식 으로든 포인터를 움직이지는 않습니다. 내부 포인터가 요소 목록의 끝을 초과하여 가리 키거나 배열이 비어 있으면 current ()는 FALSE를 반환합니다.
업데이트 1 - 새로운 관측
감사합니다.다니엘 피거 로아: 포장만으로current
함수에서 다른 결과를 얻는다.
foreach ( $list as $var ) {
print(item($list));
}
function item($list) {
return current($list);
}
출력 (데모)
BCDA // What the hell
의문 :
foreach
출력?업데이트 2
$list = array("A","B","C","D");
item2($list);
function item2($list) {
foreach ( $list as $var ) {
print(current($list));
}
}
출력 (데모보기)
AAAA // No longer BBBB when using a function
의문 :
AAAA
외부와BBBB
대부분의 PHP 버전의 함수에서
B로 시작하는 이유는 무엇입니까?
5.2 이후foreach
(신뢰할 수있게) 배열 포인터를 전진시킨다.전에루프 본문이 시작됩니다. 참조 항목FE_RESET
opcode.
$list = array("A", "B", "C","D");
foreach ($list as $var) {
break;
}
var_dump(current($list));
산출:
B
이것은 무엇을 할 수 있습니다.ZEND_OP_DATA
의사 연산 코드가 작동합니다 (실제로 문서화되지 않았습니다).
왜 그래?current()
같은 가치를 계속 주시겠습니까?
루프가 시작되기 전에,foreach
루핑하는 배열에 대한 내부 참조를 만듭니다. 루프 내에서 배열 변수가 수정되거나 참조로 전달 될 때마다 내부 참조는 배열 구조의 복사본을 만들어 변수에서 분리됩니다 (요소는 제외). 이 복사 된 값은 배열 포인터 (루프 초기화에 의해 이전에 수정 된)를 유지합니다.
이 동작은 또한 더 파괴적인unset()
조작:
$list = array('A', 'B', 'C', 'D');
foreach ($list as $key => $val) {
echo $val;
unset($list[1], $list[2], $list[3]);
}
echo "\n", print_r($list, true), "\n";
산출:
ABCD
Array
(
[0] => A
)
루프 변수를 함수에 전달
이것은 또 다른 흥미로운 시나리오입니다.
$list = array('A', 'B', 'C', 'D');
function itm($arr)
{
return current($arr);
}
foreach ($list as $item) {
print itm($list);
}
var_dump(current($list));
산출:
BCDA
bool(false)
이번에는 배열이 값에 의해 전달되므로 배열 구조가 요소가 아닌 함수로 복사됩니다.$arr
매개 변수. 앞의 예와 달리 루프의 내부 참조와$list
왜냐하면 복사가 기능 영역에서 일어나기 때문입니다.
마지막은 어떨까요?"A"
?
이것은 지금까지 가장 신비로운 행동입니다.foreach
이러한 상황에서만 목격 될 수 있습니다. 마지막 루프 반복에서 배열 포인터는 다음과 같습니다.겉으로는첫 번째 항목으로 되감기. 겉으로보기에는 루프의 끝 부분에서 요소의 끝 부분을 가리키고 있기 때문입니다 (출력의 마지막 줄에서 볼 수 있듯이).
이 문제는SWITCH_FREE
의 마지막에 실행되는 opcodeforeach
.
그렇다면 왜foreach
함수가 다르다면?
다음 코드를 살펴보십시오.
function item2($arr)
{
foreach ($arr as $var) {
print(current($arr));
}
var_dump(current($arr));
}
$list = array("A","B","C","D");
item2($list);
산출:
AAAA
string(1) "A"
이 경우 내부 참조는foreach
배열의 복사본으로 초기화됩니다 (refcount> 1이기 때문에).$arr
상징.
더 심해질 수 있습니까?
당연하지! 참조를 사용하거나 여러 번 중첩 할 때 심지어 더 까다로운 결과를 얻을 수 있습니다.foreach
같은 변수에 루프.
그렇다면 어떻게 일관된 결과를 얻을 수 있습니까?
용도Iterators
또는 배열 변수를 참조 할 때 일관성있는 값을 얻는 것에 의존하지 마십시오.foreach
조작.
rewind
온 ? 그것은 함수 rewinds 배열을 의미합니까 ??? 또는 return 문이 배열에 영향을 미침 - Baba
에서PHP.net
current () 함수는 단순히 배열 요소의 값을 반환합니다. 현재 내부 포인터가 가리키고 있습니다. 그것은하지 않는다. 어떤 식 으로든 포인터를 움직이십시오.
다음 : 사용다음 것()
$list = array("A", "B", "C","D");
foreach ($list as $var) {
print(current($list));
next($list);
}
참고 : foreach 포인터를 배열의 두 번째 요소로 이동 한 때문에 첫 번째 요소가 인쇄되지 않습니다 :)
이 예제는 완전한 동작을 설명합니다 :
$list = array("A", "B", "C","D");
foreach ($list as $var) {
if(!isset($a)) reset($list); $a = 'isset';
print(current($list));
next($list);
}
출력은 ABCD입니다.
다음 사항에 유의하십시오.
As foreach relies on the internal array pointer changing it within the loop may lead to unexpected behavior.
편집 : 나는 또한 내 새로운 혼란 찾기를 공유하고 싶습니다!
예제 1 :
$list = array("A", "B", "C","D");
$list_copy = $list;
foreach ($list as $key => $val) {
current($list_copy);
echo current($list);
//next($list);
}
출력 : AAAA
예 2 :
$list = array("A", "B", "C","D");
$list_copy = $list;
foreach ($list as $key => $val) {
current($list_copy);
echo current($list);
next($list);
}
출력 : ABCD
foreach 내부에서 current () 함수를 호출 할 때 다른 배열에도 foreach 동작에 영향을줍니다 ...
예 3 :
$list = array("A", "B", "C","D");
$refcopy = &$list;
foreach ($list as $key => $val) {
if(!isset($a)) { $a = 'isset'; reset($list); }
echo current($list);
next($list);
}
출력 : ACD (WOW!비누락)
예 : 4
$list = array("A", "B", "C","D");
$refcopy = &$list;
foreach ($list as $key => $val) {
echo current($list);
next($list);
}
출력 : BCD
foreach 루프에서 어떤 일이 일어날 지 정확히 결정할 수 없습니다 !!!
글쎄, 나는 이것이 실제적인 단서를 가지고 있지는 않지만, 과제가 평가 / 처리되는 방식과 관련이 있다고 생각된다. 재미를 위해 나는 이것을 시도했고 그것은 또 다른 결과를 낳았다.incorrect
행동:
$arr = array('A', 'B', 'C', 'D');
function itm($val) {
return current($val);
}
foreach ($arr as $item) {
print itm($arr);
}
결과 : BCDA
그래서 내 추측은 여기서 일어나는 일은 함수 호출이 현재의 평가를 ~ 올바른 방식으로 강제 실행한다는 것입니다. 또한 ABCD 대신 BCDA를 얻는 이유는 내부 포인터가 처음에 증가하고 (B를 가리키고) EN에서 다시 A로 리셋되기 때문일 것입니다.
이 줄을PHP doc:
할당은 원래 변수를 새 값으로 복사 (값에 의한 대입)하므로 하나에 대한 변경 사항은 다른 변수에 영향을 미치지 않습니다. 밀집한 루프 안에 큰 배열과 같은 것을 복사해야하는 경우에도 관련성이 있습니다.
나는 이것이 정말로 대답으로 간주되지 않지만 나는 당신의 질문을 좋아했고 조금 기여하고 싶다고 생각합니다.
$arr
을 기준으로하여BBBB
.codepad.viper-7.com/6MxdFr - Leri
배열의 복사본이 foreach에 의해 만들어졌다하더라도 AAAA를 얻었지만 현재의 PHP 안정 버전에서는 그렇지 못합니다.
나는이 질문에 대한 답을 찾지 못했기 때문에 설명하려고한다.
첫 번째 반복 전에foreach
$list
실제로 복사되지 않습니다. 만참조 카운팅의$list
따라서 첫 번째 반복에서 첫 번째 값은$list
에서 복사됩니다.$var
포인터는 두 번째 요소로 이동합니다.$list
과실제 사본의$list
될 것입니다. 그래서 전화 할 때current
포인터가 두 번째 요소를 가리 키지 만 두 번째 이상의 반복에서는 포인터가 수정되지 않으므로실제 사본의$list
존재한다current
항상 두 번째 요소를 출력합니다.
편집하다:
나는 함께 놀았다.debug_zval_dump
이 예기치 않은 동작을 이해하려면
<pre>
<?php
$list = array("A", "B", "C","D");
echo '<h1>Ref count before entering foreach:</h1><br>';
debug_zval_dump($list); echo '<br><br>';
$i = 0;
echo '<h1>Ref count in foreach:</h1><br>';
foreach ($list as $var) {
$i++;
echo '<b>Iteration #'.$i.':</b> ';
debug_zval_dump($list);
echo '<br>';
}
$list = array("A", "B", "C","D"); //re-assign array to avoid confusion
echo '<h1>Ref count before entering foreach that calls method "item" and passes array by value:</h1><br>';
debug_zval_dump($list);
$i = 0;
echo '<h1>Ref count in foreach that calls method "item" and passes array by value:</h1><br>';
foreach ( $list as $var ) {
$i++;
item($list, $i);
}
function item($list, $i) {
echo '<b>Iteration #'.$i.':</b> ';
debug_zval_dump($list);
}
$list = array("A", "B", "C","D"); //re-assign array to avoid confusion
echo '<h1>Ref count before entering foreach that calls method "item" and passes array by reference:</h1><br>';
debug_zval_dump($list);
$i = 0;
echo '<h1>Ref count in foreach that calls method "item" and passes array by reference:</h1><br>';
foreach ( $list as $var ) {
$i++;
itemWithRef($list, $i);
}
function itemWithRef(&$list, $i) {
echo '<b>Iteration #'.$i.':</b> ';
debug_zval_dump($list);
}
그리고 다음과 같은 결과를 얻었습니다 :
Ref count before entering foreach:
array(4) refcount(2){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(1) }
Ref count in foreach:
Iteration #1: array(4) refcount(3){ [0]=> string(1) "A" refcount(2) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(1) }
Iteration #2: array(4) refcount(3){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(2) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(1) }
Iteration #3: array(4) refcount(3){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(2) [3]=> string(1) "D" refcount(1) }
Iteration #4: array(4) refcount(3){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(2) }
Ref count before entering foreach that calls method "item" and passes array by value:
array(4) refcount(2){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(1) } Ref count in foreach that calls method "item" and passes array by value:
Iteration #1: array(4) refcount(5){ [0]=> string(1) "A" refcount(2) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(1) } Iteration #2: array(4) refcount(5){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(2) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(1) } Iteration #3: array(4) refcount(5){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(2) [3]=> string(1) "D" refcount(1) } Iteration #4: array(4) refcount(5){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(2) } Ref count before entering foreach that calls method "item" and passes array by reference:
array(4) refcount(2){ [0]=> string(1) "A" refcount(1) [1]=> string(1) "B" refcount(1) [2]=> string(1) "C" refcount(1) [3]=> string(1) "D" refcount(1) } Ref count in foreach that calls method "item" and passes array by reference:
Iteration #1: array(4) refcount(1){ [0]=> string(1) "A" refcount(4) [1]=> string(1) "B" refcount(3) [2]=> string(1) "C" refcount(3) [3]=> string(1) "D" refcount(3) } Iteration #2: array(4) refcount(1){ [0]=> string(1) "A" refcount(3) [1]=> string(1) "B" refcount(4) [2]=> string(1) "C" refcount(3) [3]=> string(1) "D" refcount(3) } Iteration #3: array(4) refcount(1){ [0]=> string(1) "A" refcount(3) [1]=> string(1) "B" refcount(3) [2]=> string(1) "C" refcount(4) [3]=> string(1) "D" refcount(3) } Iteration #4: array(4) refcount(1){ [0]=> string(1) "A" refcount(3) [1]=> string(1) "B" refcount(3) [2]=> string(1) "C" refcount(3) [3]=> string(1) "D" refcount(4) }
출력은 약간 혼란 스럽습니다.
첫 번째 예에서foreach
내부 복사본을 만들었습니다.$list
그래서 참조 카운트는 2였습니다 (결과에서 4debug_zval_dump
하나 추가refCount
). 두 번째 예제 (값 전달)refCount
3로 증가했습니다.$list
기능을 위해 복사되었습니다. 세 번째 예에서 count는 1로 유지되었으므로$list
가치에 의해 전달되었습니다. 왜 그런지 깨달을 시간이 필요합니다. 이 결과 공유에서 포인트를 얻으면.
내가 말할 수있는 것은 우리가 값으로 배열을 통과했을 때foreach
반복되는 배열을 전달하고 있었지만 참조로 전달되면기발한
$list
. 문제는 왜foreach
그 배열을 지나가는거야?
거짓말 일 경우 사용하는 코드. 말 그대로 문자가 같은 코드처럼 보일 수도 있지만 변수는 그렇지 않습니다 (http://3v4l.org/jainJ).
실제 질문에 답하기 위해 일관된 결과를 얻으려면 올바른 도구를 사용하십시오.
배열 값을 가진 변수가 필요하면 다음과 같이 할당하십시오.
$list = array(....);
현재 값을 가져와야하는 경우그배열, 사용전에그만큼foreach
:
$current = current($list);
내부foreach
이 변수 이름은 같을 수 있지만 값이 다를 수 있습니다 (상상해보십시오!).
필요한 경우흐름각 반복 당 가치, 그것을 사용하십시오 :
foreach ($list as $current) {
...
}
만나다$current
?
오 이런, 그래, 그렇게 쉬웠다. 잠깐, 이미 일관된 결과가 있습니다. 오, 그리고 나 자신을 속일 수 없다는 것이 쉬운 일이었습니다. 예! ;)
로그의 경우 : 변수를 함수 매개 변수로 전달하면이를 새 변수로 만듭니다. 심지어 참조 (즉, 설명).
확실하지 않은 경우 PHP 참조를 사용하지 마십시오. 또는 심지어 변수 :http://3v4l.org/6p5nZ
위대한 지적. 하지만 그것은 PHP의 다른 버전으로 메모리 가리키는 문제가 보인다. 또한흐름어디에서나 증가 (탐색)하지 않은 현재 위치 만 제공하므로 올바른 결과를 얻지 못합니다. 다른 방법으로 PHP의 다른 버전을 다음과 시작점을 해석하는 방법으로 해결할 수 있습니다.다시 놓기루프 안에 몇 가지 조건이 있습니다. (그런데 루핑하고 현재를 사용하여 다음 prev는 이미 var에 객체가있는 것처럼 좋은 방법이 아닙니다 :) 당신이 선택한 것은 무엇입니까? 이것이 작동하도록하는 한 가지 방법입니다.
<?php
$list = array("A", "B", "C","D");
$flag =0;
foreach ($list as $var) {
if($flag==0)
{
reset($list);
$flag=1;
}
print(current($list));
next($list);
}
출력은 ABCD입니다. 에서보기http://3v4l.org/5Hm5Y
$list = array("A", "B", "C","D");
foreach ($list as $var) {
echo $var;
}
그것을해야한다.
current
foreach 내부에서 특정 출력을 얻는 방법이 아닙니다. - Charles
사용 당신은 이미 일어난 일을 알고 있습니다!
$list = array('A', 'B', 'C','D');
foreach ($list as $var) {
var_dump(current($list));
}
당신을 도울 수 있습니다!
arrays
과foreach
태그도 있기 때문에, IMO, 그것은 그것에 속한다. 동의하지 않으면 내 변경 내용을 되돌립니다. :) - Leri