개발 꿀팁/PHP

php 하층 작동 메커니즘과 원리

Jammie 2022. 6. 28. 17:14
반응형

1PHP의 디자인 컨셉과 특징
다중 프로세스 모델: PHP는 다중 프로세스이므로프로세스 모델은 서로 다른 요청 간에 간섭하지 않기 때문에 하나의 요청을 중단하는 것이 전체 서비스에 영향을 미치지 않을 수 있으며, 물론 시대가 발전하고 PHP도 이미 멀티스레드 모델을 지원하고 있다.

약유형언어: C/C++, Java, C# 등과 달리 PHP는 약한 언어다.한 변수의 유형이 처음부터 변하지 않는다고 확정되는 것이 아니라, 실행 중에 비로소 확정되고 암묵적이거나 명시적인 유형의 전환이 발생할 수 있는 메커니즘의 유연성웹 개발에서 편리하고 효율적이다.

엔진 (Zend) + 구성 요소 (ex)t)는 내부 커플링을 감소시킨다.

중간층(sapi), 차단 webserver와 PHP.

문법은 쉽고 유연해서 규범이 별로 없다

2PHP 코어 아키텍처
PHP 코어 아키텍처는 다음과 같다.아래에서 위로 간단하게 네 가지 계층으로 나눌 수 있습니다.

Zend 엔진: 순수 C 구현은 PHP의 커널 부분으로, PHP 코드 번역(어법, 구문 해석 등의 일련의 컴파일 과정)을 opcode 처리로 실행 가능하게 하고, 그에 상응하는 처리 방법을 실현하며, 기본적인 데이터 구조(hashtable, oo), 메모리 할당 및 관리, 그에 상응하는 API 방법을 외부 호출에 제공하는 모든 핵심이며, 모든 주변 기능은 Zend를 중심으로 구현된다.

Extensions: Zend 엔진을 둘러싸고, extensions는 컴포넌트식으로 다양한 기초 서비스를 제공하고 있으며, 우리가 흔히 볼 수 있는 각종 내장 함수(array 시리즈), 표준 라이브러리 등은 extension을 통해 구현됩니다.

Sapi:전체칭은 Server Application Programming Interface 서비스측 응용 프로그래밍 인터페이스입니다. Sapi는 일련의 후크 함수를 통해 PHP와 주변 데이터를 상호 작용할 수 있습니다. 이것은 PHP의 매우 우아하고 성공적인 설계입니다. Sapi를 통해 성공적으로 PHP 자체와 상위 계층을 디커플링 분리하여 PHP는 서로 다른 대응에 대해 더 이상 생각하지 않을 수 있습니다.호환이 가능하기 때문에 애플리케이션 자체도 자신의 특성에 맞게 다른 처리 방식을 구현할 수 있다.
자주 사용되는 일부 SAPI는 다음과 같습니다.
apache2handler: 이것은 apache를 Webserver로서 mod_PHP 모드로 동작할 때의 처리 방식이며, 현재 가장 널리 사용되고 있다.
cgi: 웹서버와 PHP가 직접 상호작용하는 또 다른 방식, 즉 잘 알려진 fastcgi 프로토콜로 최근 올해 fastcgi+PHP가 점점 더 많이 응용되고 있으며 비동기 웹서버가 유일하게 지원하는 방식이다.
CLI: 명령줄 호출 적용 모드

상위 애플리케이션: 이것은 우리가 평소에 쓰는 PHP 프로그램으로, 웹서버를 통한 웹 애플리케이션 구현, 명령줄에서 스크립트 방식으로 실행되는 등 다양한 sapi 방식을 통해 다양한 애플리케이션 패턴을 얻을 수 있습니다.
3PHP의 실행 흐름

PHP는 하나의 전형적인 동적 언어 실행 과정을 구현했다: 코드를 얻은 후, 구문 해석, 구문 해석 등의 단계를 거친 후 소스 프로그램은 하나의 명령어(opcodes)로 번역되고, ZEND 가상 머신들은 이러한 명령어들을 순차적으로 실행함으로써 작업을 완료한다.PHP 자체는 C로 구현되기 때문에 최종적으로 호출되는 것도 모두 C의 함수이며, 실제로 PHP는 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_IS_EQUAL_SPEC_CV_CONST:판단상등 a==1

ZEND_IS_IDENTICAL_SPEC_CV_CONST:판단상등 a===1

4 Zend 엔진 소개
Zend 엔진 PHP로서커널에는 많은 고전적인 설계 메커니즘이 있는데, 주로 다음과 같다.

4.1 해시T 구현able 데이터 기관:

해시테이블은 Z입니다end의 핵심 데이터 구조.PHP에서 흔히 볼 수 있는 거의 모든 기능을 구현하기 위해 사용하는 것을 알고 있습니다.PHP 배열이 대표적인 응용 프로그램이며, 또한 zend 내에서부, 함수 기호표, 글로벌 변수 등도 해시테이블을 기반으로 한다.
Zend hashtable은 전형적인 해시테이블 해시구조를 구현함과 동시에 하나의 양방향 체인테이블을 부가하여 제공합니다.배열의 순방향, 역방향으로 트래버스 하는 기능을 한다.그 구조는 아래 그림과 같다

해시테이블에는 key->value 형식의 해시구조가 있고, 양방향 체인 테이블모드가 있어 빠른 검색과 선형적인 트래킹을 쉽게 지원할 수 있다.
해시구조:Zend의 해시구조는 전형적인 해시테이블 모델로, 연쇄테이블 방식으로 충돌을 해결한다.zend의 hash table은 자급자족하는 데이터 노드라는 점에 유의해야 한다해시 테이블이 가득 차면 그 자체가 동적으로 2배로 확장돼 원소의 위치가 바뀐다.초기 사이즈는 모두 8입니다.또한, key->value를 빠르게 탐색할 때 zend 자체에 최적화하여 공간을 통해 시간을 바꾸는 방식으로 속도를 높였습니다.예를 들어 각 요소에서 key의 길이를 하나의 변수 nKeyLength로 표시하여 빠르게 판정한다.
양방향 체인 테이블: Zend hash table은 하나의 체인 테이블 구조를 통해 요소의 선형적인 트래버스를 구현합니다.이론적으로, 두루마리 시계는 단방향 체인 시계로 충분합니다. 양방향 체인시계를 사용하는 것은 주요 목적이다.빠른 삭제를 위해 넘나드는 것을 피하는 것이다. Zend hash table은 배열로 사용할 때 흔히 볼 수 있는 관련 배열도 순차적으로 색인된 숫자로 사용할 수 있고, 심지어 둘의 혼합도 허용하는 복합형 구조이다.
PHP 연결 배열: 연결 배열은 전형적인 hash_table 응용이다.한 번의 조회 과정은 아래와 같이 몇 단계를 거친다(코드에서 알 수 있듯이 이것은 흔히 볼 수 있는 hash 조회 과정이며, 추가된다.빠른 판정 가속 찾기:

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;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
    PHP 인덱스 배열: 인덱스 배열은 우리가 흔히 볼 수 있는 배열로 첨자를 통해 접근한다.예를 들어 arr[0], Zend HashTable은 내부적으로 정규화 처리를 하고 index 타입 key에 대해서도 마찬가지로 hash값과 nKeyLength(0)를 할당한다.내부 구성원 변수 nNextFreeElement는 현재 할당된 최대 id로 push마다 1씩 자동으로 추가됩니다.바로 이러한 정규화 처리로 PHP가 연관성과 비관련성을 혼합할 수 있게 된 것이다.push 조작의 특수성 때문에 인덱스 키의 PHP 배열에서의 순서는 첨자 크기가 아니라 push의 순서에 의해 결정된다.예를 들어 arr[1] = 2; arr[2] = 3; Zend HashTable은 double 타입의 key를 인덱스 key로 처리합니다.

    4.2 PHP 변수 구현 원리:

    PHP는 약한 유형 언어로서 변수를 제대로 구분하지 않는 유형이다.PHP는 변수가 밝혀질 때 유형을 지정할 필요가 없다.PHP는 프로그램 실행 중에 변수 타입의 암묵적인 변환을 수행할 수 있다. 다른 강한 타입의 언어와 마찬가지로 프로그램에서도 표시되는 타입의 변환을 할 수 있다.PHP 변수는 단순 유형(int, string, bool), 집합 유형(array, resource, object), 상수(const)로 나눌 수 있다.위의 모든 변수는 아래층에서 동일한 구조 zval이다.

    Zval은 Zend에서 PHP 변수를 식별하고 구현하는 또 다른 중요한 데이터 구조이다.

Zval 구조체는 크게 세 부분으로 구성된다.
type: 변수에 대해 설명하는 형식( 정수)을 지정합니다., 문자열, 배열 등)
refcount&is_ref: 사용인용 횟수 구현 (자세한 내용은 나중에 자세히 설명)
value:핵심부분,변수가저장된실관계 데이터
Zvalue는 변수의 실제를 저장하는 데 사용됩니다.데이터. 여러 종류를 저장하기 때문에 zvalue는 하나의 union입니다.약유형도 가능해졌다.

PHP 변수 유형과 실제 스토리지 대응 관계는 다음과 같습니다.다음:

1   IS_LONG   -> lvalue2   IS_DOUBLE -> dvalue3   IS_ARRAY  -> ht4   IS_STRING -> str5   IS_RESOURCE -> lvalue
  • 1
  • 2
  • 3
  • 4
  • 5
    4.2.1 정수, 부동 소수점 수 변수
    정수, 부동 소수점 수는 PHP의 기본 유형이다하나는 단순형 변수다.정수와 부동 소수점 수는 zvalue에 직접 값을 저장한다.유형은 각각 롱(long)과 더블(double)이다.
    zvalue 구조에서 알 수 있듯이, 맞아요.정수형은 c와 같은 강한 타입의 언어와 달리, PHP는 int, unsignedint, long, long long 등의 유형을 구분하지 않으며, 그에 대한 정수형은 한 종류밖에 없다.long입니다. 이를 통해 PHP에서 정수의 값의 범위는 고정 불변의 것이 아니라 컴파일러의 자릿수에 의해 결정됨을 알 수 있습니다.
    부동 소수점 수에 대하여, 유사한 정수에 대하여, 그것도 구분하지 않는다.플로트와 더블이 아닌 통일은 더블 한 가지 유형이다.

    PHP에서 정수 범위가 범위를 벗어나면 어쩌나어떡하지? 이럴 경우 자동으로 더블로 전환되는데 이건 조심해야 돼요. 트릭이 많이 나오거든요.

    4.2.2 문자 변수

    정수와 마찬가지로 문자 변수 역시 PHP 중기초유형과 단순형 변수.zvalue 구조를 통해 PHP에서 문자열은 실제 데이터를 가리키는 포인터와 길이 구조체로 구성된다는 점을 c++에서의 string과 비교한다.유사합니다. 실제 변수를 통해 길이를 나타내기 때문에 c와 달리 문자열은 이진 데이터(\0 포함)가 될 수 있습니다. PHP에서 문자열 길이를 구하는 것은 O(1) 동작입니다.

    문자열 신규, 수정, 추가 조작 시,PHP는 메모리를 재할당해 새로운 문자열을 생성한다.마지막으로, 보안상의 이유로 PHP는 문자열 생성 시 끝에 \0을( 를) 추가합니다.

    일반적인 문자열 스플라이싱과 속도 비교:

    다음과 같은 4가지 변수가 있다고 가정하자:strA='123'; strB= '456'; intA=123; intB=456;
    다음과 같은 문자열 스플라이싱 방법을 사용합니다.하나의 비교와 설명:
    1 res = strA.strB와 res = "strAstrB"
    이 경우 zend는 다시 mal을 하게 됩니다.loc는 메모리 1개에 해당하는 처리속도가 보통이다.
    2 strA = strA.strB
    이런 게 제일 빠릅니다. zend가 당합니다.프론트 strA 기반 직접 relloc, 중복 복사 피
    3 res = intA.intB
    이런 속도는 비교적 느리다, 암묵적인 격식을 갖춰야 하기 때문이다.식 전환, 실제 프로그램 작성에서도 최대한 피하도록 유의해야 한다.
    4 strA = sprintf ("%s%s, strA, strB)
    이것은 가장 느린 방법이 될 수 있다. 왜냐하면 sprintf는 PHP에서 하나의 언어구조가 아니며, 그 자체가 포맷 인식과 처리에 많은 시간이 소요되며, 그 자체 메커니즘도 malloc이다.하지만 sprintf 방식이 가장 가독성 있고 사실이에요.가운데는 상황에 따라 유연하게 선택할 수 있다.

    4.2.3 배열 변수

    PHP 배열이 Zend Has를 통과함hTable 천연으로 구현됩니다.

    포레치 운영은 어떻게 이뤄지는가.하나의 배열에 대한 포어치는 해시테이블 내의 양방향 체인 테이블을 통해 이루어진다.인덱스 배열의 경우 foreach를 통해 for보다 훨씬 효율적이며, key->val을 생략한다.ue의 찾기. count 작업은 HashTable -> NumOfElements, O(1) 작업을 직접 호출합니다.'123'과 같은 문자열의 경우 zend는 그 정수 형태로 변환됩니다.arr['123']과 arr[123]은 같은 값입니다

    4.2.4 자원 변수

    자원 유형 변수는 PHP 중 가장 복잡하다종변량도 복합형 구조다.

    PHP의 zval은 광범위한 수를 나타낼 수 있다유형에 따르면, 그러나 사용자 정의 데이터 유형에 대해서는 충분히 기술하기 어렵다.이러한 복합 구조들을 효과적으로 묘사할 방법이 없기 때문에, 그들에게 전통적인 연산자를 사용할 방법도 없다.이 문제를 해결하려면, 하나만 통과하면 된다.본질적으로 임의의 식별자(label)가 포인터를 인용하는 방식을 자원이라고 한다.

    zval에서 resourc에 대하여e,lval은 포인터로 사용되며 자원이 있는 주소를 직접 가리킨다.Resource는 임의의 복합구조일 수 있으며, 우리에게 익숙한 mysqli, fsock, memcached 등은 모두자원.
    리소스 사용 방법:

    1 등록: 1에 대하여사용자 정의 데이터 유형을 리소스로 사용하려면 이 항목을 선택합니다.우선 등록이 필요하며, zend는 이를 위해 전역 고유 표시를 할당한다.
    2 리소스 가져오기변수: 자원에 대해 zend는 id-> 실제 데이터의 hash_tale을 유지합니다.하나의 resource에 대해 zval에서그 아이디만 기록돼 있다.fetch의 경우 id를 통해 hash_table에서 구체적인 값을 찾아 돌아온다.
    3 자원 파괴: 자금소스의 데이터 유형은 다양하다.젠드 자체로는 그것을 없앨 방법이 없다.따라서 사용자가 자원을 등록할 때 파기함수를 제공해야 한다.unset 자원이면 zend는 해당 함수를 호출하여 구조를 완성한다.전역 리소스 테이블에서 이 항목을 삭제합니다.
    자원은 장기간 체류할 수 있다이를 인용하는 모든 변수가 작용영역을 벗어나 있을 뿐만 아니라, 하나의 요청이 끝나고 새로운 요청이 생긴 후에도 말이다.이러한 자원을 지속적 자원이라고 부른다.일부러 파기하지 않는 한 SAPI를 관통하는 전체 라이프사이클이 지속됩니다.자원을 오래 지속하면 어느 정도 성능을 높일 수 있는 경우가 많다.예를 들어, mysql_pconnect의 경우, pemalloc을 통해 메모리를 할당하여 요청이 끝날 때 메모리를 할당하지 않습니다.석방. zend에게는 둘 그 자체로 구분이 되지 않는다.

    4-3. PHP 변수 관리—인용 카운트와 쓰기 시간 복사:

    참조 카운트가 메모리에 저장됨수신, 문자열 조작 등 광범위하게 사용되고 있습니다.Zval의 참조 카운트는 멤버 변수 is_ref와 ref_count를 통해 구현되며, 참조를 통해 구현됩니다.카운트, 여러 변수가 동일한 데이터를 공유할 수 있습니다.빈번한 복사로 인한 대량의 소모를 피한다.zend는 값을 할당할 때 동일한 zval을 동시에 ref_count++로, unset할 때 대응하는 ref_count-1을 가리킨다.ref_count만 감산0시가 되어야 실제 파기 작업을 수행할 수 있습니다.인용 대입의 경우 zend는 is_ref를 1로 수정한다.

    PHP 변수 통과 참조카운트를 사용하여 변수 공유 데이터를 실현합니다. 변수 값 중 하나를 변경하면 어떻게 됩니까?변수를 쓰려고 할 때 Zend가 zval을 가리킨다면여러 변수가 공유되면 ref_count가 1인 zval을 복사해 원래 zval의 refcount를 감산하는 과정을 'zval 분리'라고 한다.글쓰기가 있을 때만 zend를 복사하기 때문에 copy-on-write라고도 합니다.(쓰기 중 복사)

    인용형 변수의 경우,비인용형과 반대로 참조할 수 있는 변수끼리 번들여야 하며, 하나의 변수를 수정하면 모든 번들 변수가 수정된다.
    4- 4. PHP 로컬 및 글로벌 변수 구현:

    PHP 안의 국소변수와 전역변수는 어떻게 실현됩니까?요청 시 PHP는 두 개의 심볼 테이블(symbol_table과 active_symbol_table)을 볼 수 있으며, 전자는 글로벌 변수를 유지하는 데 사용됩니다.후자는 현재 활성화된 변수 기호 테이블을 가리키는 포인터이며, 프로그램이 함수에 들어갈 때 zend는 기호 테이블 x를 할당하면서 active_symbol_table을 a로 가리킨다.이를 통해 대역적·국소적 변수의 구분이 가능해진다.

    변수 값 가져오기: PHP의 기호 테이블은 hash_t입니다able은 각 변수에 고유 식별자를 할당하고, 획득 시 식별자에 따라 표에서 해당 zval을 찾아 반환한다.

    함수에서 전역 변수를 사용합니다. 함수에서 우리는 강조할 수 있습니다.글로벌을 선언하여 글로벌 변수를 사용한다.active_symbol_table에서 symbol_table의 동명 변수에 대한 참조(참조 변수의 값을 업데이트하려면 모두 함께 업데이트)를 만들고, symbol_table에 동명 변수가 없으면 먼저 만듭니다.
반응형