> 백엔드 개발 > PHP 튜토리얼 > PHP 실행 원리

PHP 실행 원리

高洛峰
풀어 주다: 2023-03-05 15:58:02
원래의
2666명이 탐색했습니다.

PHP 실행 원리

php는 매우 간단한 응용 프로그램과 매우 높은 개발 효율성을 갖춘 언어로, 약한 유형의 변수를 사용하면 프로그래머가 많은 수의 변수를 정의할 필요가 없습니다. 유형 변환 등의 노력 웹 개발에 적합한 동적 언어입니다.

1. PHP 설계의 원리와 특징

  • 다중 프로세스 모델: 프로세스가 서로 영향을 받지 않으며 프로세스의 리소스 활용도가 향상됩니다. 더 빠르고 편리하다

  • 약한 유형의 언어: C, C++, Java와 같은 강력한 유형의 언어와 달리 PHP에서는 변수의 유형이 처음에 결정되지 않습니다. 런타임 시 결정되며 암시적 또는 명시적으로 유형 변환이 가능하므로 프로그래머는 변수 유형

  • Zend 엔진 + 구성 요소에 주의를 기울일 필요가 없습니다. ext) 모드는 내부 결합을 줄입니다

  • 중간 계층(sapi)은 웹 서버와 PHP를 격리합니다

  • 구문은 간단하고 유연합니다. 사양이 적습니다. 이것은 장단점이 있습니다. . .

2. PHP의 4계층 시스템

PHP执行原理

php는 위에서 아래까지 총 4계층 시스템을 가지고 있습니다.

  • Zend 엔진: Zend는 전적으로 C로 구현되었으며 PHP의 핵심 부분입니다. Zend는 PHP 코드를 실행 가능한 opcode로 변환하고 해당 처리 방법을 처리 및 구현합니다. Brother Niao의 블로그)에서는 기본 데이터 구조, 메모리 할당 및 관리를 구현하고 모든 것의 핵심인 외부 사용을 위한 해당 API 메서드를 제공합니다.

  • Extensions: Zend 엔진 주변에는 일반적으로 사용되는 내장 함수 배열, 표준 라이브러리 등을 통해 다양한 기본 서비스를 제공합니다. 사용자는 기능 확장 및 기타 목적을 달성하기 위해 필요에 따라 자체 확장을 구현할 수도 있습니다. 예를 들어 현재 Tieba에서 사용하는 PHP 중간 계층 및 서식 있는 텍스트 구문 분석은 확장의 일반적인 응용 프로그램입니다.

  • Sapi: Sapi의 전체 이름은 Server Application Programing Interface이며, 이는 Sapi가 일련의 후크를 통해 PHP가 주변 데이터와 상호 작용할 수 있게 해줍니다. 이는 매우 우아하고 성공적인 PHP 디자인입니다. PHP 자체는 상위 계층 애플리케이션에서 성공적으로 분리되고 분리됩니다. PHP는 더 이상 다른 애플리케이션과 호환되는 방법을 고려할 수 없으며 애플리케이션 자체도 구현할 수 있습니다. 자체 특성에 따라 처리 방식이 다릅니다.

  • 상위 애플리케이션: 프로그래머가 작성한 애플리케이션 프로그램으로, 웹 서버를 통해 웹 애플리케이션을 구현하는 등 다양한 sapi 방법을 통해 다양한 애플리케이션 모드를 얻습니다. 명령줄 등에서 스크립트로 실행

3. Sapi

앞서 언급했듯이 Sapi는 일련의 인터페이스를 통해 외부 애플리케이션이 PHP와 상호 작용할 수 있도록 합니다. 다양한 애플리케이션 특성에 따라 교환할 수 있으며 특정 처리 방법을 구현할 수 있습니다. 일반적인 sapi는 다음과 같습니다.

  • apache2handler: Apache를 웹 서버로 사용하며 MOD_PHP 모드에서 실행할 때의 처리 방법도 다음과 같습니다. 현재 가장 널리 사용되는 것

  • cgi: 이는 웹서버와 PHP 사이의 또 다른 상호작용 방식으로, fastcgi 프로토콜입니다.

  • cli: 명령어 디버깅 응용 모드

4. PHP 코드 실행 과정

PHP执行原理

그림에서 볼 수 있듯이 PHP는 다음을 통해 구현됩니다. Zend 엔진 일반적인 동적 언어 실행 프로세스가 설명됩니다. 코드 조각이 얻어지고 어휘 분석, 구문 분석 및 기타 단계 후에 소스 프로그램이 명령(opcode)으로 변환되고 Zend 가상 머신이 이러한 명령을 순차적으로 실행합니다. . PHP 자체는 C 언어로 구현되므로 최종적으로 호출되는 함수도 C 언어 함수입니다.

PHP 실행의 핵심은 명령어를 하나씩 번역하는 것, 즉 opcode

Opcode는 PHP 프로그램 실행의 가장 기본 단위입니다. Opcode는 두 개의 매개변수(op1, op2), 반환 값 및 처리 기능으로 구성됩니다. PHP 프로그램은 궁극적으로 opcode 처리 기능 세트의 순차적 실행으로 변환됩니다.

일반적으로 사용되는 여러 함수:

  • END_ASSIGN_SPEC_CV_CV_HANDLER: 변수 할당(a=b)

  • ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER: 함수 호출

  • ZEND_CONCAT_SPEC_CV_CV_HANDLER: 문자열 연결 a.b

  • ZEND_ADD_SPEC_CV_CONST_HANDLER: 추가 a+2

  • ZEND_ _EQUAL_SPEC_CV_CONST: 판단 동등 a==1

  • ZEND_IS_IDENTICAL_SPEC_CV_CONST: 동등 판단 a===1

5. Zend 엔진 소개

PHP의 핵심인 Zend 엔진의 주요 설계 메커니즘은 다음과 같습니다.

5.1 HashTable 데이터 구조 구현

HashTable은 Zend의 핵심 데이터 구조로 거의 모든 것을 구현하는 데 사용됩니다. PHP의 함수는 Data array() 입니다. 또한 Zend 내에서는 HashTable을 통해 함수 기호 테이블, 파노라마 변수 등의 기능을 구현합니다.

Zend 해시 테이블은 일반적인 해시 테이블 해시 구조를 구현함과 동시에 양방향 연결 리스트를 붙여 정방향, 역방향, 배열 순회 기능을 제공합니다.

PHP执行原理

보시다시피 해시 테이블은 키->값 형태의 해시 구조와 이중 연결 리스트 모드를 모두 갖고 있어 빠른 검색과 선형 순회를 지원하는 데 매우 편리합니다.
해시 구조 : Zend의 해시 구조는 링크드 리스트를 통해 충돌을 해결하는 전형적인 해시 테이블 모델입니다. zend의 해시 테이블은 자체 성장하는 데이터 구조라는 점에 유의해야 합니다. 해시 테이블 수가 가득 차면 동적으로 2배로 확장되고 요소의 위치가 변경됩니다. 초기 크기는 8입니다. 또한, 키->값 빠른 검색을 수행할 때 zend 자체도 공간을 시간과 교환하여 프로세스 속도를 높이기 위해 일부 최적화를 수행했습니다. 예를 들어, 빠른 결정을 위해 키 길이를 식별하기 위해 각 요소에서 nKeyLength 변수가 사용됩니다.
이중 연결 목록: Zend 해시 테이블은 연결 목록 구조를 통해 요소의 선형 순회를 구현합니다. 이론적으로는 순회를 위해 단방향 연결 목록을 사용하는 것으로 충분합니다. 양방향 연결 목록을 사용하는 주요 목적은 순회를 빠르게 삭제하고 방지하는 것입니다. Zend 해시 테이블은 배열로 사용될 때 일반적인 연관 배열을 지원하고 순차 인덱스 번호로 사용될 수도 있으며 둘을 혼합하는 것도 허용합니다.
PHP 연관 배열: 연관 배열은 일반적인 hash_table 애플리케이션입니다. 쿼리 프로세스는 다음 단계를 거칩니다(코드에서 볼 수 있듯이 이는 일반적인 해시 쿼리 프로세스이며 검색 속도를 높이기 위해 몇 가지 빠른 판단이 추가됨):

01  getKeyHashValue h;
02  index = n & nTableMask;
03  Bucket *p = arBucket[index];
04  while (p) {
05      if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
06          RETURN p->data;   
07      }
08      p=p->next;
09  }
10  RETURN FALTURE;
로그인 후 복사
로그인 후 복사

PHP 인덱스 배열 : 인덱스 배열 첨자를 통해 액세스되는 공통 배열입니다. 예를 들어 arr[0], Zend HashTable은 내부적으로 정규화되었으며, 인덱스 유형 키에도 해시 값과 nKeyLength(0)가 할당되었습니다. 내부 멤버 변수 nNextFreeElement는 현재 할당된 최대 ID이며, 푸시할 때마다 자동으로 1씩 증가합니다. PHP가 연관 데이터와 비연관 데이터의 혼합을 달성할 수 있게 하는 것은 바로 이 정규화 프로세스입니다. 푸시 작업의 특수성으로 인해 PHP 배열의 인덱스 키 순서는 첨자의 크기가 아니라 푸시 순서에 따라 결정됩니다. 예를 들어 arr[1] = 2; arr[2] = 3; Zend HashTable은 이를 인덱스 키로 취급합니다

5.2 PHP 변수의 구현 원리

PHP는 약한 유형의 언어이며 변수 유형을 엄격하게 구분하지 않습니다. PHP 변수는 단순형(int, sting, bool), 컬렉션형(array, resources, object), 상수(const)로 구분할 수 있으며, 하단의 모든 변수는 동일한 구조를 가지고 있습니다 zval

zval은 PHP 변수를 표시하고 구현하는 데 사용되는 zend의 매우 중요한 데이터 구조입니다.

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;  /* variable ref count */
    zend_uchar type;          /* active type */
    zend_uchar is_ref__gc;    /* if it is a ref variable */
};
typedef struct _zval_struct zval;
로그인 후 복사
로그인 후 복사

그 중

  • zval_value value는 변수의 실제 값, 특히 zvalue_value 공용체입니다.

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */
} zvalue_value;
로그인 후 복사
로그인 후 복사
  • zend_uint refcount__gc는 A입니다. 이 zval을 가리키는 변수(또는 기호, 기호) 수를 저장하는 데 사용되는 카운터입니다. 변수가 생성되면 refcount=1입니다. $a = $b와 같은 일반적인 할당 작업은 zval의 refcount를 1씩 늘리고 unset 작업은 이에 따라 1씩 감소합니다. PHP5.3 이전에는 참조 계산 메커니즘을 사용하여 GC를 구현했습니다. zval의 참조 횟수가 0보다 작으면 Zend 엔진은 zval을 가리키는 변수가 없다고 생각하여 GC가 차지하는 메모리 공간을 해제했습니다. zval. 그러나 때로는 상황이 그렇게 간단하지 않습니다. zval을 가리키는 변수가 설정되지 않은 경우에도 간단한 참조 카운팅 메커니즘이 순환 참조 zval을 GC할 수 없어 메모리 누수(Memory Leak)가 발생한다는 사실을 나중에 살펴보겠습니다.

  • zend_uchar 유형이 필드는 변수의 실제 유형을 나타내는 데 사용됩니다. PHP의 변수에는 네 가지 스칼라 유형(bool, int, float, string), 두 가지 복합 유형(배열, 개체) 및 두 가지 특수 유형(리소스 및 NULL)이 포함됩니다. zend 내에서 이러한 유형은 다음 매크로(코드 위치 phpsrc/Zend/zend.h)

#define IS_NULL     0
#define IS_LONG     1
#define IS_DOUBLE   2
#define IS_BOOL     3
#define IS_ARRAY    4
#define IS_OBJECT   5
#define IS_STRING   6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY   9
#define IS_CALLABLE 10
로그인 후 복사
로그인 후 복사
  • is_ref__gc에 해당합니다. 사용된 필드 변수가 참조 변수인지 여부를 표시합니다. 일반 변수의 경우 값은 0이고 참조 변수의 경우 값은 1입니다. 이 변수는 zval의 공유, 분리 등에 영향을 미칩니다

5.2.1 정수 및 부동 소수점 변수

정수 및 부동 소수점 숫자는 PHP의 기본 유형 중 하나이자 단순 변수입니다. 정수 및 부동 소수점 숫자의 경우 해당 값은 zvalue에 직접 저장됩니다. 해당 유형은 각각 long과 double입니다.
zvalue 구조에서 볼 수 있듯이 정수 유형의 경우 C와 같은 강력한 유형의 언어와 달리 PHP는 int, unsigned int, long, long long 및 기타 유형을 구분하지 않습니다. 정수만 한 가지 유형은 long입니다. 이를 통해 PHP에서 정수의 값 범위는 컴파일러 비트 수에 따라 결정되며 고정되지 않음을 알 수 있습니다. PHP에서 정수가 범위를 벗어나면 어떻게 되나요? PHP는 자동으로 정수를 부동 소수점 유형으로 변환합니다

정수와 마찬가지로 부동 소수점 숫자의 경우 float와 double을 구별하지 않고 단일 유형인 double만 통합합니다: double

5.2.2 문자 변수

정수와 마찬가지로 문자 변수도 PHP의 기본 유형이자 단순 변수입니다. PHP의 문자열은 실제 데이터에 대한 포인터와 C++의 문자열과 유사한 길이 구조로 구성된다는 것을 zvalue 구조에서 볼 수 있습니다. 길이는 c와 달리 실제 변수로 표시되므로 해당 문자열은 이진 데이터(0 포함)일 수 있습니다. 동시에 PHP에서 문자열 길이 strlen을 찾는 것은 O(1) 작업입니다

일반적인 문자열 접합 방법 및 속도 비교:

다음 4가지 변수가 있다고 가정합니다. strA='123'; strB = '456' intB=456; >이제 다음 문자열 접합 방법을 비교하고 설명합니다.
1 res = strA.strB 및 res = “strAstrB”
이 경우 zend는 메모리 조각을 다시 할당하고 이에 따라 처리합니다. , 속도는 평균입니다.
2 strA = strA.strB
이것이 가장 빠르며, zend는 반복 복사를 피하기 위해 현재 strA를 기반으로 직접 다시 할당됩니다.
3 res = intA.intB
암시적 형식 변환으로 인해 속도가 느려집니다. 필수이므로 프로그램을 작성할 때 이를 피하도록 주의해야 합니다.
4 strA = sprintf (“%s%s”, strA, strB)
sprintf는 sprintf가 아니기 때문에 가장 느린 방법입니다. PHP에서는 언어 구조가 복잡하고, 형식을 식별하고 처리하는 데 많은 시간이 걸립니다. 또한 메커니즘 자체가 malloc입니다. 그러나 sprintf 방법이 가장 읽기 쉽고 실제로는 특정 상황에 따라 유연하게 선택할 수 있습니다.

5.2.3 배열 변수
PHP의 배열은 자연스럽게 Zend Hash Table을 통해 구현됩니다.

foreach 작업을 어떻게 구현하나요? 배열의 Foreach는 해시 테이블의 이중 연결 목록을 순회하여 완료됩니다. 인덱스 배열의 경우 foreach를 통한 순회는 foreach보다 훨씬 효율적이므로 키->값을 검색할 필요가 없습니다. count 연산은 HashTable->NumOfElements, O(1) 연산을 직접 호출합니다. '123'과 같은 문자열의 경우 zend는 이를 정수 형식으로 변환합니다. arr['123'] 및 arr[123]

5.3 PHP 변수 관리-참조 카운팅 및 쓰기 시 복사
참조 카운팅은 메모리 재활용, 문자열 연산 등에 널리 사용됩니다. Zval의 참조 카운팅은 멤버 변수 is_ref 및 ref_count를 통해 구현됩니다. 참조 카운팅을 통해 여러 변수가 동일한 데이터를 공유할 수 있습니다. 잦은 복사로 인한 막대한 소비를 피하세요.

에 할당 작업을 수행할 때 zend는 변수를 동일한 zval 및 ref_count++로 지정합니다. 설정 해제 작업을 수행할 때 해당 ref_count-1이 사용됩니다. 소멸 작업은 ref_count가 0으로 감소된 경우에만 수행됩니다. 참조 할당인 경우 zend는 is_ref를 1로 수정합니다.

PHP 변수는 참조 카운팅을 통해 변수 공유 데이터를 구현합니다. 변수 중 하나의 값을 변경하면 어떻게 될까요? 변수를 작성하려고 할 때 Zend가 변수가 가리키는 zval이 여러 변수에 의해 공유되는 것을 발견하면 ref_count가 1인 zval을 복사하고 원래 zval의 refcount를 감소시킵니다. 이 프로세스를 "zval 분리"라고 합니다. ". zend는 쓰기 작업이 발생할 때만 복사 작업을 수행하는 것을 알 수 있으므로

기록 중 복사(copy-on-write)

라고도 합니다. 참조 변수의 경우, 요구사항 및 비참조 반대로 참조로 할당된

변수는 묶어야 합니다. 하나의 변수를 수정하면 묶인 모든 변수가 수정됩니다.

5.4 PHP에서 지역 변수와 전역 변수 구현:
PHP에서 지역 변수와 전역 변수는 어떻게 구현되나요? 요청에 대해 PHP는 언제든지

두 개의 기호 테이블(symbol_table 및 active_symbol_table) 을 볼 수 있으며, 그 중 전자는 전역 변수를 유지하는 데 사용됩니다. 후자는 현재 활성화된 변수 기호 테이블을 가리키는 포인터입니다. 프로그램이 함수에 들어가면 zend는 기호 테이블 x를 여기에 할당하고 active_symbol_table을 a를 가리킵니다. 이러한 방식으로 전역 변수와 지역 변수의 구별이 이루어집니다.

변수 값 얻기: PHP의 기호 테이블은 hash_table을 통해 구현되며, 각 변수에는 고유 식별자가 할당됩니다. 변수 값을 얻으면 해당 식별자에 따라 테이블에서 해당 zval을 찾아 반환합니다.

함수에서 전역 변수 사용: 함수에서는 global을 명시적으로 선언하여 전역 변수를 사용할 수 있습니다.

active_symbol_table의 Symbol_table에 동일한 이름의 변수에 대한 참조를 생성합니다(참조 변수의 값을 업데이트해야 하는 경우 동일한 이름의 변수가 없으면 모두가 함께 업데이트합니다). Symbol_table이 먼저 생성됩니다.

참고:

  • http://www.php.cn/

  • http://www.php.cn/

  • [http://www.php.cn/


PHP 실행 원리

php는 매우 간단한 응용 프로그램과 매우 높은 개발 효율성을 갖춘 언어로, 약한 유형의 변수를 사용하면 프로그래머가 많은 수의 변수를 정의할 필요가 없습니다. 유형 변환 등의 노력 웹 개발에 적합한 동적 언어입니다.

1. PHP 설계의 원리와 특징

  • 다중 프로세스 모델: 프로세스가 서로 영향을 받지 않으며 프로세스의 리소스 활용도가 향상됩니다. 더 빠르고 편리하다

  • 약한 유형의 언어: C, C++, Java와 같은 강력한 유형의 언어와 달리 PHP에서는 변수의 유형이 처음에 결정되지 않습니다. 런타임 시 결정되며 암시적 또는 명시적으로 유형 변환이 가능하므로 프로그래머는 변수 유형

  • Zend 엔진 + 구성 요소에 주의를 기울일 필요가 없습니다. ext) 모드는 내부 결합을 줄입니다

  • 중간 계층(sapi)은 웹 서버와 PHP를 격리합니다

  • 구문은 간단하고 유연합니다. 사양이 적습니다. 이것은 장단점이 있습니다. . .

2. PHP의 4계층 시스템

PHP执行原理

php는 위에서 아래까지 총 4계층 시스템을 가지고 있습니다.

  • Zend 엔진: Zend는 전적으로 C로 구현되었으며 PHP의 핵심 부분입니다. Zend는 PHP 코드를 실행 가능한 opcode로 변환하고 해당 처리 방법을 처리 및 구현합니다. Brother Niao의 블로그)에서는 기본 데이터 구조, 메모리 할당 및 관리를 구현하고 모든 것의 핵심인 외부 사용을 위한 해당 API 메서드를 제공합니다.

  • Extensions: Zend 엔진 주변에는 일반적으로 사용되는 내장 함수 배열, 표준 라이브러리 등을 통해 다양한 기본 서비스를 제공합니다. 사용자는 기능 확장 및 기타 목적을 달성하기 위해 필요에 따라 자체 확장을 구현할 수도 있습니다. 예를 들어 현재 Tieba에서 사용하는 PHP 중간 계층 및 서식 있는 텍스트 구문 분석은 확장의 일반적인 응용 프로그램입니다.

  • Sapi: Sapi의 전체 이름은 Server Application Programing Interface이며, 이는 Sapi가 일련의 후크를 통해 PHP가 주변 데이터와 상호 작용할 수 있게 해줍니다. 이는 매우 우아하고 성공적인 PHP 디자인입니다. PHP 자체는 상위 계층 애플리케이션에서 성공적으로 분리되고 분리됩니다. PHP는 더 이상 다른 애플리케이션과 호환되는 방법을 고려할 수 없으며 애플리케이션 자체도 구현할 수 있습니다. 자체 특성에 따라 처리 방식이 다릅니다.

  • 상위 애플리케이션: 프로그래머가 작성한 애플리케이션 프로그램으로, 웹 서버를 통해 웹 애플리케이션을 구현하는 등 다양한 sapi 방법을 통해 다양한 애플리케이션 모드를 얻습니다. 명령줄 등에서 스크립트로 실행

3. Sapi

앞서 언급했듯이 Sapi는 일련의 인터페이스를 통해 외부 애플리케이션이 PHP와 상호 작용할 수 있도록 합니다. 다양한 애플리케이션 특성에 따라 교환할 수 있으며 특정 처리 방법을 구현할 수 있습니다. 일반적인 sapi는 다음과 같습니다.

  • apache2handler: Apache를 웹 서버로 사용하며 MOD_PHP 모드에서 실행할 때의 처리 방법도 다음과 같습니다. 현재 가장 널리 사용되는 것

  • cgi: 이는 웹서버와 PHP 사이의 또 다른 상호작용 방식으로, fastcgi 프로토콜입니다.

  • cli: 명령어 디버깅 응용 모드

4. PHP 코드 실행 과정

PHP执行原理

그림에서 볼 수 있듯이 PHP는 다음을 통해 구현됩니다. Zend 엔진 일반적인 동적 언어 실행 프로세스가 설명됩니다. 코드 조각이 얻어지고 어휘 분석, 구문 분석 및 기타 단계 후에 소스 프로그램이 명령(opcode)으로 변환되고 Zend 가상 머신이 이러한 명령을 순차적으로 실행합니다. . PHP 자체는 C 언어로 구현되므로 최종적으로 호출되는 함수도 C 언어 함수입니다.

PHP 실행의 핵심은 명령어를 하나씩 번역하는 것, 즉 opcode

Opcode는 PHP 프로그램 실행의 가장 기본 단위입니다. Opcode는 두 개의 매개변수(op1, op2), 반환 값 및 처리 기능으로 구성됩니다. PHP 프로그램은 궁극적으로 opcode 처리 기능 세트의 순차적 실행으로 변환됩니다.

일반적으로 사용되는 여러 함수:

  • END_ASSIGN_SPEC_CV_CV_HANDLER: 변수 할당(a=b)

  • ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER: 함수 호출

  • ZEND_CONCAT_SPEC_CV_CV_HANDLER: 문자열 연결 a.b

  • ZEND_ADD_SPEC_CV_CONST_HANDLER: 추가 a+2

  • ZEND_ _EQUAL_SPEC_CV_CONST: 판단 동등 a==1

  • ZEND_IS_IDENTICAL_SPEC_CV_CONST: 동등 판단 a===1

5. Zend 엔진 소개

PHP의 핵심인 Zend 엔진의 주요 설계 메커니즘은 다음과 같습니다.

5.1 HashTable 데이터 구조 구현

HashTable은 Zend의 핵심 데이터 구조로 거의 모든 것을 구현하는 데 사용됩니다. PHP의 함수는 Data array() 입니다. 또한 Zend 내에서는 HashTable을 통해 함수 기호 테이블, 파노라마 변수 등의 기능을 구현합니다.

Zend 해시 테이블은 일반적인 해시 테이블 해시 구조를 구현함과 동시에 양방향 연결 리스트를 붙여 정방향, 역방향, 배열 순회 기능을 제공합니다.

PHP执行原理

보시다시피 해시 테이블은 키->값 형태의 해시 구조와 이중 연결 리스트 모드를 모두 갖고 있어 빠른 검색과 선형 순회를 지원하는 데 매우 편리합니다.
해시 구조 : Zend의 해시 구조는 링크드 리스트를 통해 충돌을 해결하는 전형적인 해시 테이블 모델입니다. zend의 해시 테이블은 자체 성장하는 데이터 구조라는 점에 유의해야 합니다. 해시 테이블 수가 가득 차면 동적으로 2배로 확장되고 요소의 위치가 변경됩니다. 초기 크기는 8입니다. 또한, 키->값 빠른 검색을 수행할 때 zend 자체도 공간을 시간과 교환하여 프로세스 속도를 높이기 위해 일부 최적화를 수행했습니다. 예를 들어, 빠른 결정을 위해 키 길이를 식별하기 위해 각 요소에서 nKeyLength 변수가 사용됩니다.
이중 연결 목록: Zend 해시 테이블은 연결 목록 구조를 통해 요소의 선형 순회를 구현합니다. 이론적으로는 순회를 위해 단방향 연결 목록을 사용하는 것으로 충분합니다. 양방향 연결 목록을 사용하는 주요 목적은 순회를 빠르게 삭제하고 방지하는 것입니다. Zend 해시 테이블은 배열로 사용될 때 일반적인 연관 배열을 지원하고 순차 인덱스 번호로 사용될 수도 있으며 둘을 혼합하는 것도 허용합니다.
PHP 연관 배열: 연관 배열은 일반적인 hash_table 애플리케이션입니다. 쿼리 프로세스는 다음 단계를 거칩니다(코드에서 볼 수 있듯이 이는 일반적인 해시 쿼리 프로세스이며 검색 속도를 높이기 위해 몇 가지 빠른 판단이 추가됨):

01  getKeyHashValue h;
02  index = n & nTableMask;
03  Bucket *p = arBucket[index];
04  while (p) {
05      if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
06          RETURN p->data;   
07      }
08      p=p->next;
09  }
10  RETURN FALTURE;
로그인 후 복사
로그인 후 복사

PHP 인덱스 배열 : 인덱스 배열 첨자를 통해 액세스되는 공통 배열입니다. 예를 들어 arr[0], Zend HashTable은 내부적으로 정규화되었으며, 인덱스 유형 키에도 해시 값과 nKeyLength(0)가 할당되었습니다. 내부 멤버 변수 nNextFreeElement는 현재 할당된 최대 ID이며, 푸시할 때마다 자동으로 1씩 증가합니다. PHP가 연관 데이터와 비연관 데이터의 혼합을 달성할 수 있게 하는 것은 바로 이 정규화 프로세스입니다. 푸시 작업의 특수성으로 인해 PHP 배열의 인덱스 키 순서는 첨자의 크기가 아니라 푸시 순서에 따라 결정됩니다. 예를 들어 arr[1] = 2; arr[2] = 3; Zend HashTable은 이를 인덱스 키로 취급합니다

5.2 PHP 변수의 구현 원리

PHP는 약한 유형의 언어이며 변수 유형을 엄격하게 구분하지 않습니다. PHP 변수는 단순형(int, sting, bool), 컬렉션형(array, resources, object), 상수(const)로 구분할 수 있으며, 하단의 모든 변수는 동일한 구조를 가지고 있습니다 zval

zval은 PHP 변수를 표시하고 구현하는 데 사용되는 zend의 매우 중요한 데이터 구조입니다.

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;  /* variable ref count */
    zend_uchar type;          /* active type */
    zend_uchar is_ref__gc;    /* if it is a ref variable */
};
typedef struct _zval_struct zval;
로그인 후 복사
로그인 후 복사

그 중

  • zval_value value는 변수의 실제 값, 특히 zvalue_value 공용체입니다.

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */
} zvalue_value;
로그인 후 복사
로그인 후 복사
  • zend_uint refcount__gc는 A입니다. 이 zval을 가리키는 변수(또는 기호, 기호) 수를 저장하는 데 사용되는 카운터입니다. 변수가 생성되면 refcount=1입니다. $a = $b와 같은 일반적인 할당 작업은 zval의 refcount를 1씩 늘리고 unset 작업은 이에 따라 1씩 감소합니다. PHP5.3 이전에는 참조 계산 메커니즘을 사용하여 GC를 구현했습니다. zval의 참조 횟수가 0보다 작으면 Zend 엔진은 zval을 가리키는 변수가 없다고 생각하여 GC가 차지하는 메모리 공간을 해제했습니다. zval. 그러나 때로는 상황이 그렇게 간단하지 않습니다. zval을 가리키는 변수가 설정되지 않은 경우에도 간단한 참조 카운팅 메커니즘이 순환 참조 zval을 GC할 수 없어 메모리 누수(Memory Leak)가 발생한다는 사실을 나중에 살펴보겠습니다.

  • zend_uchar 유형이 필드는 변수의 실제 유형을 나타내는 데 사용됩니다. PHP의 변수에는 네 가지 스칼라 유형(bool, int, float, string), 두 가지 복합 유형(배열, 개체) 및 두 가지 특수 유형(리소스 및 NULL)이 포함됩니다. zend 내에서 이러한 유형은 다음 매크로(코드 위치 phpsrc/Zend/zend.h)

#define IS_NULL     0
#define IS_LONG     1
#define IS_DOUBLE   2
#define IS_BOOL     3
#define IS_ARRAY    4
#define IS_OBJECT   5
#define IS_STRING   6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY   9
#define IS_CALLABLE 10
로그인 후 복사
로그인 후 복사
  • is_ref__gc에 해당합니다. 사용된 필드 변수가 참조 변수인지 여부를 표시합니다. 일반 변수의 경우 값은 0이고 참조 변수의 경우 값은 1입니다. 이 변수는 zval의 공유, 분리 등에 영향을 미칩니다

5.2.1 정수 및 부동 소수점 변수

정수 및 부동 소수점 숫자는 PHP의 기본 유형 중 하나이자 단순 변수입니다. 정수 및 부동 소수점 숫자의 경우 해당 값은 zvalue에 직접 저장됩니다. 해당 유형은 각각 long과 double입니다.
zvalue 구조에서 볼 수 있듯이 정수 유형의 경우 C와 같은 강력한 유형의 언어와 달리 PHP는 int, unsigned int, long, long long 및 기타 유형을 구분하지 않습니다. 정수만 한 가지 유형은 long입니다. 이를 통해 PHP에서 정수의 값 범위는 컴파일러 비트 수에 따라 결정되며 고정되지 않음을 알 수 있습니다. PHP에서 정수가 범위를 벗어나면 어떻게 되나요? PHP는 자동으로 정수를 부동 소수점 유형으로 변환합니다

정수와 마찬가지로 부동 소수점 숫자의 경우 float와 double을 구별하지 않고 단일 유형인 double만 통합합니다: double

5.2.2 문자 변수

정수와 마찬가지로 문자 변수도 PHP의 기본 유형이자 단순 변수입니다. PHP의 문자열은 실제 데이터에 대한 포인터와 C++의 문자열과 유사한 길이 구조로 구성된다는 것을 zvalue 구조에서 볼 수 있습니다. 길이는 c와 달리 실제 변수로 표시되므로 해당 문자열은 이진 데이터(0 포함)일 수 있습니다. 동시에 PHP에서 문자열 길이 strlen을 찾는 것은 O(1) 작업입니다

일반적인 문자열 접합 방법 및 속도 비교:

다음과 같은 4가지 변수가 있다고 가정합니다. strA='123'; strB = '456'; >이제 다음 문자열 접합 방법을 비교하고 설명합니다.
1 res = strA.strB 및 res = “strAstrB”
이 경우 zend는 메모리 조각을 다시 할당하고 이에 따라 처리합니다. , 속도는 평균입니다.
2 strA = strA.strB
이것이 가장 빠르며, zend는 반복 복사를 피하기 위해 현재 strA를 기반으로 직접 다시 할당됩니다.
3 res = intA.intB
암시적 형식 변환으로 인해 속도가 느려집니다. 필수이므로 프로그램을 작성할 때 이를 피하도록 주의해야 합니다.
4 strA = sprintf (“%s%s”, strA, strB)
sprintf는 sprintf가 아니기 때문에 가장 느린 방법입니다. PHP에서는 언어 구조가 복잡하고, 형식을 식별하고 처리하는 데 많은 시간이 걸립니다. 또한 메커니즘 자체가 malloc입니다. 그러나 sprintf 방법이 가장 읽기 쉽고 실제로는 특정 상황에 따라 유연하게 선택할 수 있습니다.

5.2.3 배열 변수
PHP의 배열은 자연스럽게 Zend Hash Table을 통해 구현됩니다.

foreach 작업을 어떻게 구현하나요? 배열의 Foreach는 해시 테이블의 이중 연결 목록을 순회하여 완료됩니다. 인덱스 배열의 경우 foreach를 통한 순회는 foreach보다 훨씬 효율적이므로 키->값을 검색할 필요가 없습니다. count 연산은 HashTable->NumOfElements, O(1) 연산을 직접 호출합니다. '123'과 같은 문자열의 경우 zend는 이를 정수 형식으로 변환합니다. arr['123'] 및 arr[123]

5.3 PHP 변수 관리-참조 카운팅 및 쓰기 시 복사
참조 카운팅은 메모리 재활용, 문자열 연산 등에 널리 사용됩니다. Zval의 참조 카운팅은 멤버 변수 is_ref 및 ref_count를 통해 구현됩니다. 참조 카운팅을 통해 여러 변수가 동일한 데이터를 공유할 수 있습니다. 잦은 복사로 인한 막대한 소비를 피하세요.

에 할당 작업을 수행할 때 zend는 변수를 동일한 zval 및 ref_count++로 지정합니다. 설정 해제 작업을 수행할 때 해당 ref_count-1이 사용됩니다. 소멸 작업은 ref_count가 0으로 감소된 경우에만 수행됩니다. 참조 할당인 경우 zend는 is_ref를 1로 수정합니다.

PHP 변수는 참조 카운팅을 통해 변수 공유 데이터를 구현합니다. 변수 값 중 하나가 변경되면 어떻게 되나요? 변수를 작성하려고 할 때 Zend가 변수가 가리키는 zval이 여러 변수에 의해 공유되는 것을 발견하면 ref_count가 1인 zval을 복사하고 원래 zval의 refcount를 감소시킵니다. 이 프로세스를 "zval 분리"라고 합니다. ". zend는 쓰기 작업이 발생할 때만 복사 작업을 수행하는 것을 알 수 있으므로

기록 중 복사(copy-on-write)

라고도 합니다. 참조 변수의 경우, 요구사항 및 비참조 반대로 참조로 할당된

변수는 묶어야 합니다. 하나의 변수를 수정하면 묶인 모든 변수가 수정됩니다.

5.4 PHP에서 지역 변수와 전역 변수 구현:
PHP에서 지역 변수와 전역 변수는 어떻게 구현되나요? 요청에 대해 PHP는 언제든지

두 개의 기호 테이블(symbol_table 및 active_symbol_table) 을 볼 수 있으며, 그 중 전자는 전역 변수를 유지하는 데 사용됩니다. 후자는 현재 활성화된 변수 기호 테이블을 가리키는 포인터입니다. 프로그램이 함수에 들어가면 zend는 기호 테이블 x를 여기에 할당하고 active_symbol_table을 a를 가리킵니다. 이러한 방식으로 전역 변수와 지역 변수의 구별이 이루어집니다.

변수 값 얻기: PHP의 기호 테이블은 hash_table을 통해 구현됩니다. 각 변수에는 고유 식별자가 할당됩니다. 변수를 얻으면 해당 zval이 테이블에서 발견되고 식별자에 따라 반환됩니다.

함수에서 전역 변수 사용: 함수에서는 global을 명시적으로 선언하여 전역 변수를 사용할 수 있습니다.

active_symbol_table의 Symbol_table에 동일한 이름의 변수에 대한 참조를 생성합니다(참조 변수의 값을 업데이트해야 하는 경우 동일한 이름의 변수가 없으면 모두가 함께 업데이트합니다). Symbol_table이 먼저 생성됩니다.

더 많은 PHP 실행 원리 및 관련 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!

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