바이두 엔지니어들이 말하는 PHP 함수의 구현 원리와 성능 분석(1)
서문 참고 출처:
어떤 언어에서든 함수는 가장 기본적인 구성 요소입니다. PHP 함수의 특징은 무엇입니까? 함수 호출은 어떻게 구현되나요? PHP 기능의 성능은 어떻습니까? 사용법에 대한 제안이 있습니까? 이 기사에서는 구현을 이해하면서 PHP 프로그램을 더 잘 작성하기 위해 원리를 분석하고 실제 성능 테스트와 결합하여 이러한 질문에 답하려고 노력할 것입니다. 동시에 몇 가지 일반적인 PHP 기능이 소개됩니다.
PHP 함수 분류
PHP에서 함수를 가로로 나누면 사용자 함수(내장 함수)와 내부 함수(내장 함수) 두 가지로 나누어집니다. 전자는 프로그램 내에서 사용자가 맞춤화한 일부 함수와 메소드이고, 후자는 PHP 자체에서 제공하는 다양한 라이브러리 함수(예: sprintf, array_push 등)입니다. 사용자는 나중에 소개할 확장 메서드를 통해 라이브러리 함수를 작성할 수도 있습니다. 사용자 기능은 함수(function)와 메소드(class method)로 나눌 수 있습니다. 본 글에서는 이 세 가지 기능을 각각 분석하고 테스트하겠습니다.
PHP 함수 구현
PHP 함수는 최종적으로 어떻게 실행되나요?
이 질문에 답하기 위해 먼저 PHP 코드가 실행되는 과정을 살펴보겠습니다.
그림 1에서 볼 수 있듯이 PHP는 일반적인 동적 언어 실행 프로세스를 구현합니다. 코드 조각을 얻은 후 어휘 분석, 구문 분석 및 기타 단계를 거친 후 소스 프로그램이 명령어(opcode)를 생성하고 ZEND 가상 머신은 이러한 명령어를 순서대로 실행하여 작업을 완료합니다. PHP 자체가 C로 구현되어 있기 때문에 최종적으로 호출되는 함수는 모두 C 함수입니다. 사실 PHP는 C로 개발된 소프트웨어라고 볼 수 있습니다. 위의 설명에서 PHP의 함수 실행은 호출을 위한 opcode로 변환된다는 것을 쉽게 알 수 있습니다.
zend는 각 함수에 대해 다음 데이터 구조를 통해 설명합니다.
여기서 type은 함수 유형(사용자 함수, 내장 함수, 오버로드된 함수)을 나타냅니다. 공통에는 함수 이름, 매개변수 정보, 함수 플래그(일반 함수, 정적 메서드, 추상 메서드) 등 함수의 기본 정보가 포함됩니다. 또한, 사용자 함수에 대해서는 내부 변수 등을 기록하는 함수 기호 테이블도 있는데 이에 대해서는 나중에 자세히 설명하겠습니다. Zend는 대규모 해시 테이블인 전역 function_table을 유지 관리합니다. 함수가 호출되면 먼저 함수 이름을 기반으로 테이블에서 해당 zend_function을 찾습니다. 함수를 호출할 때 가상 머신은 유형에 따라 호출 방법을 결정합니다. 함수 유형에 따라 실행 원칙이 다릅니다.
내장 함수
내장 함수는 본질적으로 실제 C 함수입니다. 각 내장 함수에 대해 PHP는 최종 컴파일 후에 zif_xxxx라는 함수로 확장됩니다. 예를 들어, 우리의 공통 sprintf는 맨 아래 레이어에 해당합니다. .zif_sprintf. Zend가 실행 중일 때 내장 함수를 찾으면 단순히 전달 작업을 수행합니다.
Zend는 매개변수 획득, 배열 작업, 메모리 할당 등을 포함하여 호출을 위한 일련의 API를 제공합니다. 내장 함수의 매개변수는 zend_parse_parameters 메소드를 통해 얻습니다. 배열, 문자열 등의 매개변수에 대해 zend는 얕은 복사를 구현하므로 이 효율성이 매우 높습니다. PHP 내장 함수의 경우 추가 전달 호출만 제외하면 효율성은 해당 C 함수의 효율성과 거의 동일하다고 말할 수 있습니다.
내장 함수는 이를 통해 PHP에 동적으로 로드됩니다. 사용자는 필요에 따라 해당 기능을 작성할 수도 있는데, 이를 흔히 확장이라고 부릅니다. ZEND는
사용자 함수
확장을 위한 일련의 API를 제공합니다. 내장 함수에 비해 PHP를 통해 구현된 사용자 정의 함수는 실행 프로세스와 구현 원리가 완전히 다릅니다. 위에서 언급했듯이 우리는 PHP 코드가 실행을 위해 opcode로 변환된다는 것을 알고 있으며 사용자 함수도 예외는 아닙니다. 실제로 각 함수는 opcode 세트에 해당하며 이 명령 세트는 zend_function에 저장됩니다. 따라서 사용자 함수 호출은 궁극적으로 일련의 opcode 실행에 해당합니다.
》》로컬 변수 저장 및 재귀 구현
스택을 통해 함수 재귀가 완료된다는 것을 알고 있습니다. PHP에서는 이를 달성하기 위해 유사한 방법이 사용됩니다. Zend는 활성 기호 테이블(active_sym_table)을 각 PHP 함수에 할당하여 현재 함수의 모든 지역 변수 상태를 기록합니다. 모든 기호 테이블은 함수가 호출될 때마다 새로운 기호 테이블이 할당되어 스택에 푸시되는 형태로 유지됩니다. 호출이 끝나면 현재 기호 테이블이 스택에서 팝됩니다. 이를 통해 상태 보존 및 재귀가 가능해집니다.
스택 유지 관리를 위해 zend는 여기에서 이를 최적화했습니다. 스택을 시뮬레이션하기 위해 길이 N의 정적 배열을 사전 할당합니다. 정적 배열을 통해 동적 데이터 구조를 시뮬레이션하는 이 방법은 각 호출로 인한 메모리 할당을 방지하는 데도 사용됩니다. ZEND는 함수 호출이 끝날 때 현재 스택의 맨 위에 있는 기호 테이블 데이터를 정리합니다. 정적 배열의 길이가 N이기 때문에 함수 호출 수준이 N을 초과하면 프로그램은 스택 오버플로를 일으키지 않습니다. 이 경우 zend는 심볼 테이블을 할당하고 파괴하므로 성능이 많이 저하됩니다. zend에서 N의 현재 값은 32입니다.따라서 PHP 프로그램을 작성할 때 함수 호출 수준이 32개를 초과하지 않는 것이 가장 좋습니다. 물론 웹 애플리케이션이라면 함수 호출 수준 자체가 깊을 수도 있다.
》》매개변수 전달은 매개변수를 얻기 위해 zend_parse_params를 호출하는 내장 함수와 다릅니다. 사용자 함수에서 매개변수 획득은 명령을 통해 완료됩니다. 함수에 있는 매개변수 수는 함수에 있는 명령 수에 해당합니다. 구현에 있어서는 일반적인 변수 할당입니다. 위의 분석에서 알 수 있듯이 내장 함수와 비교하면 스택 테이블이 자체적으로 유지되고 각 명령이 C 함수로 실행되므로 사용자 함수의 성능이 상대적으로 훨씬 저하됩니다. 구체적인 비교 분석은 나중에. 따라서 함수에 해당 PHP 내장 함수가 있는 경우 이를 구현하기 위해 함수를 직접 다시 작성하지 마십시오.
Baidu 엔지니어가 말하는 PHP 기능의 구현 원리 및 성능 분석(1)
http://www.lai18.com/content/410091.html
위 내용은 내용적인 측면을 포함하여 바이두 엔지니어들이 설명하는 PHP 기능의 구현 원리와 성능 분석을 소개하고 있으며, PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.