>백엔드 개발 >PHP 문제 >PHP의 기본 작동 원리에 대한 자세한 소개

PHP의 기본 작동 원리에 대한 자세한 소개

王林
王林원래의
2019-09-02 13:13:174601검색

PHP의 기본 작동 원리에 대한 자세한 소개

PHP는 웹 개발에 적합한 동적 언어입니다. 좀 더 구체적으로 말하자면, C 언어를 사용하여 수많은 구성 요소 모듈을 구현하는 소프트웨어 프레임워크입니다. 강력한 UI 프레임워크입니다.

간단히 말하면, PHP 동적 언어 실행 프로세스: 코드 조각을 얻은 후 어휘 분석, 구문 분석 및 기타 단계를 거쳐 소스 프로그램이 명령어(opcode)로 변환되고 ZEND 가상 머신이 이러한 명령어를 실행합니다. 순서대로 작업을 완료합니다. PHP 자체가 C로 구현되어 있으므로 최종적으로 호출되는 함수도 C 함수입니다. 사실 PHP는 C로 개발된 소프트웨어라고 볼 수 있습니다.

1. PHP의 설계 개념 및 특징

1. 다중 프로세스 모델: PHP는 다중 프로세스 모델이므로 서로 다른 요청이 서로 간섭하지 않습니다. 이를 통해 하나의 요청이 실패할 수 있습니다. 현재 PHP는 멀티스레딩 모델도 지원합니다.

2. 약한 유형의 언어: C/C++, JAVA, C# 및 기타 언어와 달리 PHP는 약한 유형의 언어입니다. 변수의 유형은 처음에 결정되지 않으며, 암시적 또는 명시적 유형 변환이 발생할 수 있습니다. 이 메커니즘의 유연성은 나중에 PHP에서 논의됩니다. 에 자세히 나와 있습니다.

3. 엔진(Zend) + 컴포넌트(ext) 모델은 내부 결합을 줄입니다.

4. 중간 계층(sapi) Sapi의 전체 이름은 웹 서버와 PHP를 분리하는 서버 응용 프로그래밍 인터페이스입니다.

5. 구문은 너무 많은 사양 없이 간단하고 유연합니다. 단점은 스타일의 혼합으로 이어집니다.

2. PHP의 4계층 시스템

PHP의 핵심 아키텍처는 다음과 같습니다.

PHP의 기본 작동 원리에 대한 자세한 소개

PHP는 아래에서 위로 4계층 시스템입니다.

1 Zend는 완전히 다음과 같이 구현됩니다. 순수 C이며 PHP입니다. 핵심 부분에서는 PHP 코드(어휘 및 구문 분석과 같은 일련의 컴파일 프로세스)를 실행 가능한 opcode 처리로 변환하고 해당 처리 방법을 구현하고 기본 데이터 구조(예: 해시 테이블, OO)를 구현했습니다. 그리고 메모리 할당 메커니즘, 그리고 모든 주변 기능이 Zend를 중심으로 구현되는 외부 호출에 대한 해당 API 메서드를 제공합니다.

2. Extensions: Extension은 Zend 엔진을 중심으로 다양한 기본 서비스를 컴포넌트 기반으로 제공합니다. 우리가 흔히 사용하는 다양한 내장 기능(어레이 시리즈), 표준 라이브러리 등도 모두 Extension을 통해 구현됩니다. 필요에 따라 확장을 사용하십시오. 자신만의 확장을 구현하기 위한 일반적인 애플리케이션입니다.

3. Sapi: Sapi의 전체 이름은 서버 애플리케이션 프로그래밍 인터페이스입니다. Sapi는 PHP가 일련의 후크 기능을 통해 주변 데이터와 상호 작용할 수 있게 해줍니다. 이것은 매우 우아하고 성공적인 PHP 디자인입니다. 이는 sapi를 통해 성공적으로 달성되었습니다. PHP 자체를 상위 계층 응용 프로그램과 분리하고 격리함으로써 PHP는 더 이상 다른 응용 프로그램과 호환되는 방법을 고려할 수 없으며 응용 프로그램 자체도 자체 특성에 따라 다른 처리 방법을 구현할 수 있습니다.

4. 상위 계층 애플리케이션: 이것은 우리가 일반적으로 작성하는 PHP 프로그램입니다. 다양한 spai 방법을 통해 다양한 애플리케이션 모드를 얻을 수 있으며, 웹 서버를 통해 웹 애플리케이션을 구현하는 방법, 명령줄에서 스크립트 모드로 실행하는 방법 등이 있습니다.

우리는 고성능 엔진(Zend) + 올바른 바퀴(Ext) + 올바른 트랙(Sapi)이 필요합니다.

3. Sapi

Sapi를 사용하면 일련의 인터페이스를 통해 PHP와 데이터를 교환하고 다양한 애플리케이션 특성에 따라 특정 처리 방법을 구현할 수 있습니다.

1: apache를 기반으로 합니다. 웹서버로서 mod_PHP 모드에서 실행될 때의 처리 방법은 현재 가장 널리 사용되는 방법이기도 합니다.

2. cgi: 이것은 유명한 fastcgi 프로토콜인 PHP 사이의 또 다른 직접적인 상호 작용 방법입니다. 최근에는 fastcgi+PHP가 점점 더 많이 사용되고 있으며, 이는 또한 일반적인 비동기 웹 서버에서 지원하는 유일한 방법이기도 합니다. nginx 서버; fastcgi는 단순히 PHP의 확장입니다.

웹 서버가 시작될 때 FastCGI 프로세스 관리자(IIS ISAPI 또는 Apache 모듈) 로드

FastCGI 프로세스 관리자는 자체적으로 초기화되고 여러 CGI 인터프리터 프로세스(여러 php-cgi 표시)를 시작한 다음 웹 서버의 연결을 기다립니다.

클라이언트 요청이 웹 서버에 도달하면 FastCGI 프로세스 관리자가 CGI 인터프리터를 선택하고 연결합니다. 웹 서버는 CGI 환경 변수와 표준 입력을 FastCGI 하위 프로세스 php-cgi로 보냅니다.

FastCGI 하위 프로세스는 처리를 완료한 후 동일한 연결에서 표준 출력 및 오류 정보를 웹 서버로 반환합니다. FastCGI 하위 프로세스가 연결을 닫으면 요청이 처리됩니다. 그런 다음 FastCGI 하위 프로세스는 FastCGI 프로세스 관리자(웹 서버에서 실행)의 다음 연결을 기다리고 처리합니다. CGI 모드에서는 이 시점에서 php-cgi가 종료됩니다.

위의 경우 CGI가 일반적으로 얼마나 느린지 상상할 수 있습니다. PHP에 대한 모든 웹 요청은 php.ini를 다시 구문 분석하고, 모든 확장을 다시 로드하고, 모든 데이터 구조를 다시 초기화해야 합니다. FastCGI를 사용하면 이 모든 작업이 프로세스가 시작될 때 한 번만 발생합니다. 추가 보너스는 지속적인 데이터베이스 연결이 작동한다는 것입니다.

PHP의 기본 작동 원리에 대한 자세한 소개

PHP의 기본 작동 원리에 대한 자세한 소개

3.cli: 명령줄 호출을 위한 응용 프로그램 모드

명령줄 인터페이스( 영어: 명령줄 인터페이스(약어: CLI)는 그래픽 사용자 인터페이스가 대중화되기 전에 가장 널리 사용된 사용자 인터페이스입니다. 일반적으로 사용자는 키보드를 통해 명령을 입력하고 컴퓨터는 명령을 받은 후 실행합니다. 그들을. 어떤 사람들은 이를 CUI(Character User Interface)라고도 합니다.
일반적으로 명령줄 인터페이스(CLI)는 그래픽 사용자 인터페이스(GUI)만큼 사용자 친화적이지 않다고 알려져 있습니다. 그러나 명령줄 인터페이스 소프트웨어는 일반적으로 사용자가 작동 명령을 기억해야 하기 때문에 자체 특성으로 인해 명령줄 인터페이스는 그래픽 사용자 인터페이스에 비해 컴퓨터 시스템 리소스를 절약합니다. 명령을 기억한다는 전제하에 명령줄 인터페이스를 사용하는 것이 그래픽 사용자 인터페이스를 사용하는 것보다 빠른 경우가 많습니다. 따라서 그래픽 사용자 인터페이스가 있는 운영 체제는 선택적 명령줄 인터페이스를 유지합니다.

4. PHP 실행 프로세스

PHP의 기본 작동 원리에 대한 자세한 소개

PHP 동적 언어 실행 프로세스: get After a 코드 조각은 어휘 분석, 구문 분석 및 기타 단계 후에 소스 프로그램이 명령(opcode)으로 변환되고 ZEND 가상 머신이 이러한 명령을 순서대로 실행하여 작업을 완료합니다. PHP 자체가 C로 구현되어 있으므로 최종적으로 호출되는 함수도 C 함수입니다. 사실 PHP는 C로 개발된 소프트웨어라고 볼 수 있습니다.

PHP 실행의 핵심은 opcode이기도 한 번역된 명령어입니다.

Opcode는 PHP 프로그램 실행의 가장 기본적인 단위입니다.

컴퓨터 과학 분야에서 연산 코드(OPCode)는 기계어 명령어를 설명하는 데 사용되며, 특정 연산을 수행하는 기계어 코드의 일부를 지정하는 것으로 OPCode의 명령어 형식과 사양을 구성합니다. 프로세서의 명령어 사양에 따라 지정됩니다.

opcode는 두 개의 매개변수(op1, op2), 반환 값 및 처리 함수로 구성됩니다. PHP 프로그램은 궁극적으로 일련의 opcode 처리 기능의 순차적 실행으로 변환됩니다.

몇 가지 일반적인 처리 기능:

ZEND_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

5. HashTable-코어 데이터 구조

#🎜🎜 #HashTable Zend의 핵심 데이터 구조입니다. 우리가 알고 있는 PHP 배열은 Zend 내에서 함수 기호 테이블, 전역 변수 등을 기반으로 합니다. 테이블에는 다음과 같은 특성이 있습니다.

1. 일반적인 키-값 쿼리를 지원합니다.

2.

#🎜 🎜#3. 노드 추가, 삭제는 O(1) 복잡함

4. 키는 혼합 유형을 지원합니다. 연관된 숫자 조합과 인덱스 배열이 동시에 있습니다

5 . 값은 혼합 유형을 지원합니다: array("string ",2332)

6. 선형 순회 지원: foreach

Zend 해시 테이블은 일반적인 해시 테이블 해시 구조를 구현합니다. 동시에 정방향 및 역방향으로 배열을 탐색하는 기능을 제공합니다. 그 구조는 아래와 같습니다:

PHP의 기본 작동 원리에 대한 자세한 소개해시 테이블에는 키->값 해시 구조와 이중 연결 리스트 모드가 모두 있는 것을 볼 수 있습니다. 빠른 검색과 선형 순회를 지원하는 것이 매우 편리합니다.

1. 해시 구조: Zend의 해시 구조는 연결 목록을 통해 충돌을 해결하는 일반적인 해시 테이블 모델입니다. zend의 해시 테이블은 자체 성장하는 데이터 구조라는 점에 유의해야 합니다. 해시 테이블 수가 가득 차면 동적으로 2배로 확장되고 요소의 위치가 변경됩니다. 초기 크기는 8입니다. 또한, 키->값 빠른 검색을 수행할 때 zend 자체도 공간을 시간과 교환하여 프로세스 속도를 높이기 위해 일부 최적화를 수행했습니다. 예를 들어, 빠른 결정을 위해 키 길이를 식별하기 위해 각 요소에서 nKeyLength 변수가 사용됩니다.

2. 이중 연결 목록: Zend 해시 테이블은 연결 목록 구조를 통해 요소의 선형 순회를 구현합니다. 이론적으로는 순회를 위해 단방향 연결 목록을 사용하는 것으로 충분합니다. 이중 연결 목록을 사용하는 주요 목적은 순회를 빠르게 삭제하고 방지하는 것입니다. Zend 해시 테이블은 배열로 사용될 때 일반적인 연관 배열을 지원하고 순차 인덱스 번호로 사용될 수도 있으며 둘을 혼합하는 것도 허용합니다. PHP 연관 배열: 연관 배열은 일반적인 hash_table 애플리케이션입니다. 질의 과정은 다음과 같은 단계를 거친다. (코드에서 알 수 있듯이 이는 일반적인 해시 질의 과정이며, 검색 속도를 높이기 위해 몇 가지 빠른 판단이 추가된다.)

getKeyHashValue h;
index = n & nTableMask;
Bucket *p = arBucket[index];
while (p) {
       if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
              RETURN p->data;   
        }
        p=p->next;
}
RETURN FALTURE;

4、PHP索引数组:索引数组就是我们常见的数组,通过下标访问。例如 $arr[0],Zend HashTable内部进行了归一化处理,对于index类型key同样分配了hash值和nKeyLength(为0)。内部成员变量 nNextFreeElement就是当前分配到的最大id,每次push后自动加一。正是这种归一化处理,PHP才能够实现关联和非关联的混合。由于 push操作的特殊性,索引key在PHP数组中先后顺序并不是通过下标大小来决定,而是由push的先后决定。例如 $arr[1] = 2; $arr[2] = 3;对于double类型的key,Zend HashTable会将他当做索引key处理。

六、Hash Table变量

PHP是一门弱类型语言,本身不严格区分变量的类型。PHP在变量申明的时候不需要指定类型。

PHP在程序运行期间可能进行变量类型的隐示转换。 和其他强类型语言一样,程序中也可以进行显示的类型转换。

PHP变量可以分为简单类型(int、string、bool)、集合类型(array resource object)和常量(const)。以上所有的变量在底层都是同一种结构 zval。

Zval主要由三部分组成:

type:指定了变量所述的类型(整数、字符串、数组等)

refcount&is_ref:用来实现引用计数(后面具体介绍)

value:核心部分,存储了变量的实际数据

Zvalue是用来保存一个变量的实际数据。因为要存储多种类型,所以zvalue是一个union,也由此实现了弱类型。

引用计数在内存回收、字符串操作等地方使用非常广泛。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(写时拷贝)对于引用型变量,其要求和非引用型相反,引用赋值的变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。整数、浮点数是PHP中的基础类型之一,也是一个简单型变量。对于整数和浮点数,在zvalue中直接存储对应的值。其类型分别是long和double。

从zvalue结构中可以看出,对于整数类型,和c等强类型语言不同,PHP是不区分int、unsigned int、long、long long等类型的,对它来说,整数只有一种类型也就是long。由此,可以看出,在PHP里面,整数的取值范围是由编译器位数来决定而不是固定不变的。

对于浮点数,类似整数,它也不区分float和double而是统一只有double一种类型。在PHP中,如果整数范围越界了怎么办?这种情况下会自动转换为double类型,这个一定要小心,很多trick都是由此产生。

和整数一样,字符变量也是PHP中的基础类型和简单型变量。通过zvalue结构可以看出,在PHP中,字符串是由由指向实际数据的指针和长度结 构体组成,这点和c++中的string比较类似。由于通过一个实际变量表示长度,和c不同,它的字符串可以是2进制数据(包含\0),同时在PHP中, 求字符串长度strlen是O(1)操作。在新增、修改、追加字符串操作时,PHP都会重新分配内存生成新的字符串。最后,出于安全考虑,PHP在生成一个字符串时末尾仍然会添加\0。

常见的字符串拼接方式及速度比较:假设有如下4个变量:$strA=‘123’; $strB = ‘456’; $intA=123; intB=456;

现在对如下的几种字符串拼接方式做一个比较和说明:

$res = $strA.$strB和$res = “$strA$strB”
这种情况下,zend会重新malloc一块内存并进行相应处理,其速度一般
$strA = $strA.$strB
这种是速度最快的,zend会在当前strA基础上直接relloc,避免重复拷贝
$res = $intA.$intB
这种速度较慢,因为需要做隐式的格式转换,实际编写程序中也应该注意尽量避免
$strA = sprintf (“%s%s”,$strA.$strB);
这会是最慢的一种方式,因为sprintf在PHP中并不是一个语言结构,本身对于格式识别和处理就需要耗费比较多时间,另外本身机制

也是malloc内存。不过sprintf的方式最具可读性,实际中可以根据具体情况灵活选择。

PHP的数组通过Zend HashTable来天然实现。foreach操作如何实现?对一个数组的foreach就是通过遍历hashtable中的双向链表完成。对于索引数组,通过foreach遍 历效率比for高很多,省去了key->value的查找。count操作直接调用 HashTable->NumOfElements,O(1)操作。对于’123’这样的字符串,zend会转换为其整数形 式。$arr[‘123’]和$arr[123]是等价的

리소스 유형 변수는 PHP에서 가장 복잡한 변수이며 복합 구조이기도 합니다. PHP의 zval은 광범위한 데이터 유형을 나타낼 수 있지만 사용자 정의 데이터 유형을 완전히 설명하기는 어렵습니다. 이러한 복합 구조를 나타내는 효율적인 방법이 없기 때문에 기존 연산자를 사용할 방법이 없습니다. 이 문제를 해결하려면 리소스라고 하는 본질적으로 임의의 식별자(레이블)를 통해 포인터를 참조하기만 하면 됩니다.

zval에서는 리소스의 경우 lval이 리소스의 주소를 직접 가리키는 포인터로 사용됩니다. 리소스는 임의의 복합 구조일 수 있습니다. 친숙한 mysqli, fsock, memcached 등은 모두 리소스입니다.

리소스 사용 방법:

등록: 사용자 정의 데이터 유형의 경우 이를 리소스로 사용하려고 합니다. 먼저 이를 등록해야 하며, zend는 전역적으로 고유한 식별자를 할당합니다.

리소스 변수 가져오기: 리소스의 경우 zend는 실제 데이터의 id->hash_tale을 유지합니다. 리소스의 경우 해당 ID만 zval에 기록됩니다. 가져올 때 id를 통해 hash_table에서 특정 값을 찾아서 반환합니다.

자원 파괴: 자원의 데이터 유형은 다양합니다. Zend 자체는 그것을 파괴할 방법이 없습니다. 따라서 사용자는 리소스 등록 시 파기 기능을 제공해야 합니다.
리소스 설정을 해제하면 zend는 해당 함수를 호출하여 폐기를 완료합니다. 또한 전역 리소스 테이블에서도 삭제합니다.

리소스를 참조하는 모든 변수가 범위를 벗어난 후뿐만 아니라 요청이 종료되고 새 요청이 생성된 후에도 리소스는 오랫동안 지속될 수 있습니다. 이러한 리소스는 특별히 파기하지 않는 한 SAPI의 수명 주기 내내 유지되므로 영구 리소스라고 합니다. 많은 경우 영구 리소스는 성능을 어느 정도 향상시킬 수 있습니다. 예를 들어, 일반적인 mysql_pconnect에서 영구 리소스는 pemalloc을 통해 메모리를 할당하므로 요청이 끝날 때 해제되지 않습니다. Zend의 경우 둘 자체에는 차이가 없습니다.

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

변수 값 가져오기: PHP의 기호 테이블은 hash_table을 통해 구현됩니다. 각 변수에는 고유한 식별자가 할당됩니다. 가져올 때 해당 zval은 테이블에서 찾아 식별자에 따라 반환됩니다.

함수에서 전역 변수 사용: 함수에서는 global을 명시적으로 선언하여 전역 변수를 사용할 수 있습니다. active_symbol_table에 같은 이름의 변수에 대한 참조를 생성합니다. Symbol_table에 같은 이름의 변수가 없으면 먼저 생성됩니다.

추천 PHP 중국어 웹사이트 비디오 튜토리얼: PHP 비디오 튜토리얼

위 내용은 PHP의 기본 작동 원리에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

관련 기사

더보기