PHP foreach는 언제 복사되나요?

藏色散人
풀어 주다: 2023-04-04 21:38:01
원래의
2572명이 탐색했습니다.

이 문서에서는 PHP 5의 foreach 복사 동작을 설명합니다. PHP 내부 작동, 즉 zvals, refcount 및 쓰기 시 복사 동작에 대한 지식이 필요합니다.

PHP foreach는 언제 복사되나요?

PHP의 foreach는 매우 깔끔하고 명확한 언어 구조입니다. 아직도 어떤 사람들은 그것이 느리다고 생각하기 때문에 그것을 사용하는 것을 좋아하지 않습니다. 공통 이름을 지정하는 한 가지 이유는 foreach가 반복하는 배열을 복사하기 때문입니다.

따라서 일부 사람들은 더 직관적이고 직접적인 대신

$keys = array_keys($array);
$size = count($array);
for ($i = 0; $i < $size; $i++) {
    $key   = $keys[$i];
    $value = $array[$key];

    // ...
}
로그인 후 복사

라고 쓰는 것을 제안합니다.

foreach ($array as $key => $value) {
    // ...
}
로그인 후 복사

여기에는 두 가지 문제가 있습니다.

미세 최적화는 나쁩니다. 이는 단지 시간만 낭비하고 측정 가능한 성능 향상으로 이어지지 않는 경우가 많습니다.

foreach의 복사 동작은 대부분의 사람들이 생각하는 것보다 조금 더 복잡합니다. 일반적으로 "최적화된" 버전은 원래 버전보다 속도가 느립니다.

foreach는 언제 복사하나요?

foreach가 얼마나 복사하는지 여부는 다음 세 가지 사항에 따라 달라집니다.

반복된 배열이 참조되는지 여부, 참조 횟수가 얼마나 높은지, 반복이 참조로 수행되는지 여부입니다.

No reference, refcount == 1

아래 코드에서 $array는 참조되지 않고 refcount는 1입니다. 이 경우 foreach는 배열(증명)을 복사하지 않습니다. 이는 foreach가 항상 참조 없이 반복된 배열을 복사한다는 일반적인 믿음과 반대입니다.

test();
function test() {
    $array = range(0, 100000);
    foreach ($array as $key => $value) {
        // ...
    }
}
로그인 후 복사

이유는 간단합니다. foreach가 $array를 수정하는 유일한 곳은 내부 배열 포인터이기 때문입니다. 이는 예상된 동작이므로 예방 조치가 필요하지 않습니다.

Unreferenced, refcount > 1

아래 코드는 이전 코드와 매우 유사해 보입니다. 유일한 차이점은 이제 배열이 매개변수로 전달된다는 것입니다. 이는 사소한 차이처럼 보일 수 있지만 foreach의 동작을 변경합니다.

이제 값이 아닌 배열 구조를 복사합니다(증명; 복사된 구조인지 알고 싶다면 이 스크립트와 해당 스크립트를 비교하세요. 첫 번째는 구조만 복사하고 두 번째는 둘 다 복사합니다.

$array = range(0, 100000);
test($array);
function test($array) {
    foreach ($array as $key => $value) {
        // ...
    }
}
로그인 후 복사

첫눈에는 조금 이상해 보일 수 있습니다.

배열이 매개변수로 전달되면 복사되지만 함수에 정의된 경우 복사되지 않는 이유는 배열 zval이 이제 다중 공유에 있기 때문입니다. 변수 사이: 함수 외부의 $array 변수와 함수 내부의 $array 변수. foreach가 배열 구조를 복사하지 않고 배열을 반복하는 경우 함수에 있는 $array 변수의 배열 포인터뿐만 아니라 함수 외부에 있는 $array 변수의 포인터도 변경됩니다. 따라서 foreach는 배열 구조(예: 해시 테이블)를 복사해야 합니다. 반면에 값은 여전히 ​​zval을 공유할 수 있으므로 복사가 필요하지 않습니다.

Quote

다음 상황은 이전 상황과 매우 유사합니다. 유일한 차이점은 배열이 참조로 전달된다는 것입니다. 이 경우 배열은 복사(증명)되지 않습니다.

$array = range(0, 100000);
test($array);
function test(&$array) {
    foreach ($array as $key => $value) {
        // ...
    }
}
로그인 후 복사

이 경우 이전 사례에도 동일한 추론이 적용됩니다: 외부 $array 및 내부 $array 공유 zvals. 차이점은 이제 참조(isref == 1)라는 점입니다. 따라서 이 경우 내부 배열에 대한 모든 변경 사항은 외부 배열에도 적용됩니다. 따라서 내부 배열의 배열 포인터가 변경되면 외부 배열의 배열 포인터도 변경되어야 합니다. 이것이 foreach에 복사가 필요하지 않은 이유입니다.

참조로 반복

위의 예는 모두 값으로 반복됩니다. 참조 반복의 경우 동일한 규칙이 적용되지만 값 참조를 추가하면 배열 값의 복사 동작이 변경됩니다(구조 복사와 관련된 동작은 동일하게 유지됨).

"unreferenced, refcount == 1" 사례는 변경되지 않았습니다. 참조 반복은 $ 값에 변경 사항이 있는 경우 배열이 복사되지 않도록(증명) 원래 배열을 변경하려는 것을 의미합니다.

"참조된" 사례도 동일하게 유지됩니다. 이 경우 $value를 변경하면 반복된 배열(증명)을 참조하는 모든 변수가 변경되어야 합니다.

이제 배열 구조와 해당 값을 복사해야 하므로 "참조되지 않음, 참조 개수 > 1"인 경우만 변경되었습니다. 그렇지 않으면 함수 외부의 $array 변수의 배열 포인터가 변경되고 $value를 변경하면 외부 $array 값도 변경되기 때문입니다(증명).

요약

foreach는 반복된 배열이 참조되지 않고 참조 개수가 1보다 큰 경우에만 배열 구조를 복사합니다.

foreach는 이전 점이 적용되고 반복이 다음과 같은 경우에만 배열 값도 복사합니다. 참조로 완료한 경우

위 내용은 PHP foreach는 언제 복사되나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿