이 글의 내용은 PHP7 커널 분석의 CGI와 FastCGI에 관한 것입니다. 1. 이제 공유합니다. 도움이 필요한 친구들이 참고할 수 있습니다
1. 변수 구조
typedef struct _zval_struct zval; typedef union _zend_value { zend_long lval; //int整形 double dval; //浮点型 zend_string *str; //string字符串 zend_array *arr; //array数组 zend_object *obj; //object对象 zend_resource *res; //resource资源类型 zend_reference *ref; //引用类型,通过&$var_name定义的 } zend_value; struct _zval_struct { zend_value value; //变量实际的value union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, //变量类型 zend_uchar type_flags, //类型掩码,不同的类型会有不同的几种属性,内存管理会用到 zend_uchar const_flags, zend_uchar reserved) } v; uint32_t type_info; //上面4个值的组合值,可以直接根据type_info取到4个对应位置的值 } u1; union { uint32_t var_flags; uint32_t next; //哈希表中解决哈希冲突时用到 uint32_t cache_slot; uint32_t lineno; uint32_t num_args; uint32_t fe_pos; uint32_t fe_iter_idx; } u2; };
2.
#define IS_UNDEF 0 #define IS_NULL 1 #define IS_FALSE 2 #define IS_TRUE 3 #define IS_LONG 4 #define IS_DOUBLE 5 #define IS_STRING 6 #define IS_ARRAY 7 #define IS_OBJECT 8 #define IS_RESOURCE 9 #define IS_REFERENCE 10
그 중 undef, true, false, null은 값이 없고 타입에 따라 바로 구분되는 반면, long과 double의 값은 직접 값에 저장되고 그 외의 타입은 포인터
3. String
typedef struct _zend_string zend_string; struct _zend_string { zend_refcounted_h gc; //变量引用信息,比如当前value的引用数 size_t len; //字符串长度,通过这个值保证二进制安全 char val[1]; //字符串内容,变长struct,分配时按len长度申请内存 };
4. Array
typedef struct _zend_array HashTable; typedef struct _zend_array zend_array; typedef struct _Bucket { zval val; //存储的具体value,这里嵌入了一个zval,而不是一个指针 zend_ulong h; //哈希值 zend_string *key; //key值 } Bucket; struct _zend_array { zend_refcounted_h gc; //引用计数信息 uint32_t nTableMask; //计算bucket索引时的掩码,用于散列表的计算nIndex Bucket *arData; //bucket数组 uint32_t nNumUsed; //已用bucket数 uint32_t nNumOfElements; //已有元素数,nNumOfElements <= nNumUsed,因为删除的并不是直接从arData中移除 uint32_t nTableSize; //数组的大小,为2^n,默认为8 uint32_t nInternalPointer; //数值索引,用于HashTable遍历 zend_long nNextFreeElement;//下一个空闲可用位置的数字索引 dtor_func_t pDestructor;//析构函数,销毁时调用的函数指针 };
HashTable은 주로 arData를 사용하여 요소의 저장 및 인덱싱을 구현합니다. 요소를 삽입할 때 먼저 요소를 Bucket 배열에 순서대로 삽입합니다. 위치는 idx입니다. 그런 다음 키의 해시 값에 따라 해시 테이블의 특정 위치 nIndex에 매핑하고 이 위치에 idx를 저장합니다. 검색할 때 먼저 nIndex에 매핑된 해시 테이블에서 Bucket 배열에 있는 value의 위치 idx를 가져온 다음 Bucket 배열에서 해당 요소를 꺼냅니다.
$arr["a"] = 1; $arr["b"] = 2; $arr["c"] = 3; $arr["d"] = 4; unset($arr["c"]);
해시 충돌: 충돌이 발생하면 원래 값의 위치를 새 값의 zval.u2.next에 저장한 후 원래 값 위치를 새 값으로 바꿉니다.
확장: PHP 해시 테이블의 크기는 2^n입니다. 삽입하는 동안 용량이 충분하지 않으면 삭제된 요소의 비율을 먼저 확인하고 임계값에 도달하면 삭제된 요소가 제거되고 인덱스가 다시 작성됩니다. 임계값에 도달하지 않으면 용량이 현재 크기의 2배로 확장되고 현재 버킷 배열을 새 공간에 복사한 다음 인덱스를 다시 빌드합니다.
해시 테이블 재구성: 삭제된 요소가 특정 개수에 도달하거나 용량이 확장되면 값이 Bucket 위치로 이동했거나 해시 배열 nTableSize가 변경되어 간의 매핑 관계가 발생하므로 해시 테이블을 재구성해야 합니다. 재구성 프로세스에는 실제로 배열의 버킷 값을 순회한 다음 매핑된 값을 다시 계산하고 이를 해시 테이블로 업데이트하고 삭제되지 않은 후속 값을 순서대로 이동하는 작업이 포함됩니다.
5. 참조
참조는 실제로 다른 PHP 변수를 가리키는 유형입니다. 이를 수정하면 실제로 가리키는 zval이 직접 변경됩니다. PHP에서는 간단히 이해할 수 있습니다. , 참조 변수는 & 연산자를 통해 생성됩니다. 즉, 이전 유형이 무엇이든 &는 먼저 zval이 포함된 zend_reference 구조를 생성합니다. 이 zval의 값은 원래 zval의 값을 가리킵니다. (부울, 정수 또는 부동 소수점인 경우 원래 값이 직접 복사됩니다.) 그런 다음 원래 zval의 유형이 IS_REFERENCE로 변경되고 원래 zval의 값은 새로 생성된 zend_reference 구조를 가리킵니다.typedef struct _zend_reference zend_reference; struct _zend_reference { zend_refcounted_h gc; zval val; };로그인 후 복사
6. 참조 계산
typedef struct _zend_refcounted_h { uint32_t refcount; union { struct { ZEND_ENDIAN_LOHI_3( zend_uchar type, zend_uchar flags, uint16_t gc_info) } v; uint32_t type_info; } u; } zend_refcounted_h;
$a = "time:" . time(); //$a -> zend_string_1(refcount=1) $b = $a; //$a,$b -> zend_string_1(refcount=2) $c = $b; //$a,$b,$c -> zend_string_1(refcount=3) unset($b); //$b = IS_UNDEF $a,$c -> zend_string_1(refcount=2)
7로 판단할 수 있습니다. Copy on write
$a = array(1,2); $b = &$a; $c = $a; //发生分离 $b[] = 3;
실제로는 문자열과 배열만 지원됩니다.
PHP 변수 재활용에는 활성 소멸과 자동 소멸이라는 두 가지 주요 유형이 있습니다. 활성 소멸은 설정 해제를 의미하며 자동 소멸은 반환 시 로컬 변수의 참조 개수를 뺍니다. 명시적인 반환이 없더라도 PHP는 이 작업을 자동으로 추가합니다. 원래 값이 연결 해제되면 연결 해제 후 이전 값의 참조 횟수도 확인됩니다.
$a = [1]; $a[] = &$a; unset($a);
unset($a) 이전의 참조 관계:
unset($a) 이후:
관련 권장 사항:
PHP7 커널 분석 2 I/O 모델
위 내용은 PHP7 커널 분석 3 변수의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!