요약: 여기서 읽은 PHP 버전은 PHP-7.1.0 RC3이고, 코드를 읽는 플랫폼은 linuxZTS입니다. 기사에 여러 부분이 있음을 알 수 있습니다. #ifdef ZTS # 정의 CG(v) ZEND_TSRMG (compiler_globals_id, zend_compiler_globals * , v) #else # 정의 CG(v) (compi...
여기서 읽는 PHP 버전은 PHP-7.1.0 RC3이고, 코드를 읽는 플랫폼은 linux
ZTS
기사에 여러 군데가 있는 것을 볼 수 있습니다.
1 #ifdef ZTS 2 # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) 3 #else 4 # define CG(v) (compiler_globals.v) 5 extern ZEND_API struct _zend_compiler_globals compiler_globals; 6 #endif
여기서 ZTS의 개념은 무엇입니까? 우리가 자주 사용하는 PHP는 단일에서 실행됩니다. -cgi와 같은 단일 스레드 환경에서는 요청이 들어오면 하나의 프로세스만 이를 처리합니다. 따라서 예를 들어 PHP 커널은 여러 스레드가 있을 때 스레드 안전 문제를 고려하지 않습니다. 동시에 단일 프로세스 다중 스레드 서버로 발전하고 있으며, 이때 스레드 안전 문제를 구체적으로 처리할 레이어가 필요합니다. 관리), 그러나 PHP는 기본적으로 꺼져 있습니다. 컴파일할 때 스레드로부터 안전한 버전의 PHP를 컴파일할 수 있도록 매개변수를 지정할 수 있습니다(--enable-maintainer-zts 옵션, Windows 플랫폼은 --enable-zts). ) 이것이 ZTS의 유래입니다. 예를 들어 위의 예에서 CG(V)는 non-thread safety 하에서 전역 구조compiler_globals 구조체의 v 속성을 얻고, 이를 ZEND_TSREMG 메서드를 통해 얻습니다.
zend_try_catch와 관련된 코드는 다음과 같습니다.매크로를 확장하면 다음과 같은 대략적인 코드를 볼 수 있습니다.
이게 무슨 뜻인가요? 먼저 setjmp와 longjmp를 이해해야 합니다. 이 두 함수는 Linux에서 제공하는 방법으로 코루틴의 기능을 구현하는 데 사용됩니다.
1 zend_try { 2 ...exec_try 3 } zend_catch { 4 ...exec_catch 5 } zend_end_try();#include < ;stdio.h>#include 141642a285ad26cf7e55efeead7f8373
01 { \ 02 JMP_BUF *__orig_bailout = EG(bailout); \ 03 JMP_BUF __bailout; \ 04 \ 05 EG(bailout) = &__bailout; \ 06 if (SETJMP(__bailout)==0) { 07 { 08 ...exec_try 09 } 10 } else { \ 11 EG(bailout) = __orig_bailout; 12 { 13 ...exec_catch 14 } 15 } \ 16 EG(bailout) = __orig_bailout; \ 17 }
jmp_buf env;
void foo() {
printf ("jmpn 이전");
int ret = setjmp(env)
if(ret == 0) {
return;
} else {
printf("return %dn", ret);
}
printf("jmpn 이후");
}
int main(int argc, char* argv[]) {
foo();
longjmp(env, 999);
return 0;
}// 출력:
/* jmp 이전
jmp 이후 999를 반환
*/
위의 예에서 setjmp는 프로그램 조각 1이 이니셔티브를 넘겨준 다음, longjmp를 만날 때까지 아래 프로그램을 실행하고 조각 1을 반환하는 것과 같습니다. 가 검색되고 jmp_buf가 999로 설정됩니다. 조각 1이 계속 실행되고 ret!=0이 발견되고 return 999가 출력됩니다.
좋아, 이 프로그램으로 돌아갑니다:
이 프로그램의 exec_try 코드 세그먼트에서 오류가 발생하여 반환해야 할 경우 longjmp 함수에 대한 호출이 포함되어 있습니다. 이러한 방식으로 try...catch...finnal을 호출하는 일반적인 기능이 형성됩니다.1 먼저 전역 변수에 구제금융을 저장합니다.
2 setjmp를 사용하여 점프하고 다음 프로그램을 실행합니다.3 exec_try
4 실행 exec_try 코드 세그먼트에 longjmp가 있고 longjmp가 0이 아닌 값을 반환하는 경우(일반적으로 실제로는 0이 아님) exec_catch01 { \ 02 JMP_BUF *__orig_bailout = EG(bailout); \ 03 JMP_BUF __bailout; \ 04 \ 05 EG(bailout) = &__bailout; \ 06 if (SETJMP(__bailout)==0) { 07 { 08 ...exec_try 09 } 10 } else { \ 11 EG(bailout) = __orig_bailout; 12 { 13 ...exec_catch 14 } 15 } \ 16 EG(bailout) = __orig_bailout; \ 17 }5를 실행합니다. 마지막으로 전역 변수에서 bailout을 복원합니다
여기서 두 가지 의문점이 있을 수 있습니다. exec_try에 longjmp가 없다면 어떻게 될까요? 그럼 그냥 exec_try를 직접 실행하고 exec_catch를 건너뛰세요. 이는 또한 try catch를 구현하기 위해 setjmp 및 longjmp를 사용하는 표준 방법이기도 합니다.
이 두 가지를 구현하면 goto 키워드가 함수 내부로만 이동할 수 있다는 제한 사항이 보완됩니다. 이것을 "멀리뛰기"라고 합니다.
따라서 PHP 코드에서 실행하는 함수가 예외를 발생시킬 수 있습니다. 이 방법을 사용하여 실행하려는 프로그램을 내부에 넣을 수도 있습니다.
위 내용은 PHP 커널 분석(2) 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!