사람들은 foreach를 사용하여 PHP 배열에 액세스하는 경우 순회 순서가 고정되어 있는지 묻습니다.
예:
$arr['laruence'] = 'huixinchen'
$arr['yahoo'] = 2007; ['baidu'] = 2008; foreach ($arr as $key => $val) {
//결과는 무엇인가요?
}
코드는 다음과 같습니다:
PHP에서는 배열을 사용합니다. HASH 구조(HashTable)가 구현되었습니다. PHP는 O(1) 시간 복잡도로 배열을 추가하고 삭제할 수 있도록 하는 몇 가지 메커니즘을 사용하며 선형 탐색과 무작위 액세스를 동시에 지원합니다.
우리는 PHP의 HASH 알고리즘에 대해서도 논의했습니다.
HashTable을 알아보기 전에 먼저 HashTable의 구조 정의를 살펴보겠습니다. 이해:
. 코드는 다음과 같습니다.
uint nTableSize; /* 해시 테이블 크기, 해시 값 범위*/
uint nTableMask; /* 빠른 위치 지정을 위해 nTableSize -1과 동일*/uint nNumOfElements; /* HashTable의 실제 요소 수*/
ulong nNextFreeElement; 사용 가능한 위치*/
Bucket *pInternalPointer ; /* 내부 위치 포인터는 재설정되며 현재는 이러한 순회 함수에 사용됩니다. */
Bucket *pListHead /* 선형 순회에 사용되는 헤드 요소 */
Bucket *pListTail; /* 선형 순회에 사용되는 꼬리 요소*/
Bucket **arBuckets; /* 실제 저장 컨테이너*/
dtor_func_t pDestructor;/* 요소의 소멸자(포인터) */
zend_bool persist;
unsigned char nApplyCount ; /* 루프 순회 보호*/
#if ZEND_DEBUG
int inconsistency; 🎜>
정보
예제를 통해 nApplyCount의 의미를 이해할 수 있습니다. 코드는
$arr = array(1,2, 3,4,5,);
$arr[] = &$arr;
var_export($arr); too deep - recursive dependency?
위 구조를 보면 HashTable의 경우를 알 수 있습니다. , 핵심 요소는 실제 저장소 컨테이너인 arBuckets입니다. 구조 정의를 살펴보겠습니다:
코드는 다음과 같습니다:
ulong h; /* 숫자 인덱스/ 해시 값*/
uint nKeyLength; /* 문자 인덱스 길이*/
void *pData; /* data*/
void *pDataPtr ; /* 데이터 포인터*/
struct bucket *pListNext ; /* 선형 순회에 사용되는 다음 요소 */
struct bucket *pNext; 동일한 지퍼의 다음 요소 요소*/
struct bucket *pLast /* 동일한 지퍼의 이전 요소*/char arKey[1] /* 팁 메모리 절약 및 초기화 용이*/
} 버킷
우리는 마지막 요소인 이것이 메모리를 절약하고 초기화를 용이하게 할 수 있는 유연한 배열 기술이라는 것을 알아냈습니다. 관심 있는 친구는 Google에서 유연한 배열을 검색할 수 있습니다.
h는 해시 값입니다. 숫자로 색인된 요소의 경우 h는 직접 색인 값입니다(숫자 색인은 nKeyLength=0으로 표시됨). 문자열 색인의 경우 색인 값은 arKey에 저장되고 색인의 길이는
Bucket에 저장됩니다. , 실제 데이터는 pData 포인터가 가리키는 메모리 블록에 저장됩니다. 일반적으로 이 메모리 블록은 시스템에 의해 별도로 할당됩니다. 그러나 예외가 있습니다. 즉, Bucket에 저장된 데이터가 포인터인 경우 HashTable은 시스템에 포인터를 저장하기 위한 공간 할당을 요청하지 않고 포인터를 pDataPtr에 직접 저장한 다음 pData가 해당 멤버를 가리킵니다. 이 구조의. 이를 통해 효율성이 향상되고 메모리 조각화가 줄어듭니다. 이것으로부터 우리는 PHP HashTable 디자인의 미묘함을 볼 수 있습니다. Bucket의 데이터가 포인터가 아닌 경우 pDataPtr은 NULL입니다. (이 단락은 Altair의 "Zend HashTable 상세 설명"에서 따옴)
HashTable의 pListhHead는 선형 목록 형식의 첫 번째 요소를 가리키며, 위 그림에서는 요소 1, pListTail이 가리키는 요소는 마지막 요소 0이고, 각 요소에 대해 pListNext는 빨간색 선으로 그려진 선형 구조의 다음 요소이고, pListLast는 이전 요소를 가리킵니다. 현재 내부 포인터의 배열이 순차적으로 탐색될 때 이 포인터는 현재 요소를 나타냅니다.
선형(순차적) 탐색이 수행되면 pListHead에서 시작하고 Bucket에서 pListNext/pListLast를 따릅니다.
예를 들어 foreach의 경우 생성된 opcode 시퀀스를 보면 foreach 전에 먼저 재설정할 FE_RESET이 있음을 알 수 있습니다. 배열의 내부 포인터, 즉 pInternalPointer(foreach의 경우 PHP 원리에 대한 자세한 내용은 foreach를 참조하세요.) 그런 다음 각 FE_FETCH를 통해 pInternalPointer를 증가시켜 순차 순회를 달성합니다.
마찬가지로, 순회하기 위해 각각/다음 일련의 함수를 사용할 때 배열의 내부 포인터를 이동하여 순차 순회도 구현됩니다. 여기에는
과 같은 문제가 있습니다. 다음과 같습니다:
임의 액세스 중에 해시 배열의 헤드 포인터 위치가 결정됩니다.
요소 추가 시 동일한 Hash 요소 체인의 선두와 선형 목록의 꼬리에 요소가 삽입됩니다. 즉, 선형 순회 중에 요소는 삽입 순서에 따라 순회됩니다. 이 특별한 디자인은 PHP에서 숫자 인덱싱을 사용할 때 요소의 순서가 인덱스 순서가 아닌 추가 순서에 따라 결정됩니다. 🎜>
즉, PHP에서 배열을 순회하는 순서는 요소의 순서와 동일합니다. 관련 항목을 추가하면 이제 기사 시작 부분에 있는 질문의 출력이 명확하게 알 수 있습니다. 코드는
입니다.
2007
2008
그래서, 숫자로 인덱스된 배열에서 인덱스 크기에 따라 반복하려면 foreach
가 아닌 for를 사용해야 합니다. 코드는
//지금은 고려할 수 없습니다. 순차 순회(선형 순회)입니다
}
이상은 PHP 배열(순회 순서)에 대한 심층적인 이해입니다. 더 많은 관련 글은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!