>  기사  >  백엔드 개발  >  PHP 수명주기 살펴보기

PHP 수명주기 살펴보기

coldplay.xixi
coldplay.xixi앞으로
2020-07-28 16:38:082109검색

Php 생명주기는 매우 복잡한 과정입니다. 주요 내용은 다음과 같습니다. PHP 수명주기 살펴보기

PHP 시작. CLI 또는 FPM을 실행하는 경우 C main()이 실행됩니다. apxs2 SAPI(Apache 2)와 같이 네트워크 서버에 대한 모듈로 실행되는 경우, PHP는 Apache가 시작된 직후에 시작되고 PHP가 그 중 하나인 모듈의 시작 시퀀스 실행을 시작합니다. 시작은 내부적으로 모듈 시작 단계라고 합니다. 줄여서 MINIT단계라고도 합니다.

시작되면 PHP는 하나/여러 요청을 처리하기 위해 기다립니다. PHP CLI에 관해 이야기할 때 요청은 단 하나뿐입니다: 실행할 현재 스크립트입니다. 하지만 웹 환경에 관해 이야기할 때(PHP-FPM 또는 웹 서버 모듈이어야 함) PHP는 여러 요청을 차례로 처리할 수 있습니다. 그것은 모두 웹 서버를 구성하는 방법에 따라 다릅니다. 프로세스를 종료하고 재활용하기 전에 요청 수에 제한이 없거나 특정 수의 요청을 처리하도록 지시할 수 있습니다. PHP는 스레드에서 새 요청이 처리될 때마다 요청 시작 단계를 실행합니다. 우리는 이를 RINIT라고 부릅니다.

관련 학습 권장사항: 초보부터 마스터까지 PHP 프로그래밍

main()。如果作为模块运行到网络服务器,像使用 apxs2 SAPI (Apache 2),则 PHP 在 Apache 启动后不久启动,并开始运行其模块的启动序列,PHP 就是其中之一。在内部称启动为模块启动步骤。我们也将其缩写为MINIT步骤。

一旦启动,PHP 将等待处理一个/几个请求。当我们谈论 PHP CLI时,将只有一个请求:当前脚本要运行。但是,当我们谈论 Web 环境时——应该是 PHP-FPM 或 Web 服务器模块——PHP 可以一个接一个地处理多个请求。这完全依赖于你如何配置你的 Web 服务器:你可以告诉它处理无限数量的请求,或在关闭并回收该过程之前处理特定数量的请求。每次一个新的请求在线程中要处理时,PHP 就会运行请求启动步骤。我们称之为 RINIT

相关学习推荐:PHP编程从入门到精通

请求得到处理,(可能)生成了一些内容,OK。是时候关闭请求,并准备好处理另一个请求。关闭请求调用请求关闭步骤。我们称之为RSHUTDOWN。·

当处理完X个请求(一个,几十个,数千个等),PHP 最后会自行关闭,然后结束。关闭 PHP 进程称为模块关闭步骤。缩写为 MSHUTDOWN

如果我们可以画出这些步骤,则可能会得到以下信息:

PHP 수명주기 살펴보기

并行模型

在 CLI 环境,任何事都很容易:一个进程处理一个请求:它会启动一个单独的 PHP 脚本,然后结束。CLI 环境是 Web 环境的一种特殊化,它更为复杂。

为了同时处理多个请求,你必须运行并行模型。在 PHP 中存在两种:

  • The process-based model 基于进程的模型
  • The thread-based model 基于线程的模型

使用基于进程的模型,操作系统将每个 PHP 解释器隔离到自己的进程中。这种模型在 Unix 非常普遍。每个请求都到它自己的进程。PHP-CLI、PHP-FPM 和 PHP-CGI 使用该模型。

在基于线程的模型中,每个 PHP 解释器都使用线程库隔离到线程中。这个模型主要用在 Windows 操作系统,但也可以用在大多数的 Unix中。要求 PHP 和其扩展在 ZTS 模式下被构建。

这是基于进程的模型:

PHP 수명주기 살펴보기

这是基于线程的模型:

PHP 수명주기 살펴보기

注意

作为扩展开发者,PHP 的多进程模块不是你的选择。你将需要支持它。你必须让你的扩展支持在线程环境中运行,特别是在 Windows平台下,并且必须针对它编程。

PHP 扩展钩子

你可能猜到了,PHP 引擎将在多个生命周期点触发你的扩展。我们称它们为钩子函数。你的扩展程序可以在向引擎注册时,通过声明函数钩子来声明对特定生命周期点的兴趣。
在你分析 PHP 扩展结构时(zend_module_entry 结构),这些钩子可以清晰地看到:

struct _zend_module_entry {
        unsigned short size;
        unsigned int zend_api;
        unsigned char zend_debug;
        unsigned char zts;
        const struct _zend_ini_entry *ini_entry;
        const struct _zend_module_dep *deps;
        const char *name;
        const struct _zend_function_entry *functions;
        int (*module_startup_func)(INIT_FUNC_ARGS);        /* MINIT() */
        int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);   /* MSHUTDOWN() */
        int (*request_startup_func)(INIT_FUNC_ARGS);       /* RINIT() */
        int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);  /* RSHUTDOWN() */
        void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);     /* PHPINFO() */
        const char *version;
        size_t globals_size;
#ifdef ZTS
        ts_rsrc_id* globals_id_ptr;
#else
        void* globals_ptr;
#endif
        void (*globals_ctor)(void *global);                /* GINIT() */
        void (*globals_dtor)(void *global);                /* GSHUTDOWN */
        int (*post_deactivate_func)(void);                 /* PRSHUTDOWN() */
        int module_started;
        unsigned char type;
        void *handle;
        int module_number;
        const char *build_id;
};

现在让我们看看你应该在这些钩子中编写哪种代码。

模块初始化:MINIT()

这是 PHP 进程启动步骤。在扩展的MINIT()요청이 처리되어 (아마도) 일부 콘텐츠가 생성되었습니다. 이제 요청을 종료하고 다른 요청을 처리할 준비를 할 시간입니다. 요청을 종료하면 요청 종료 단계가 호출됩니다. 이를 RSHUTDOWN이라고 합니다. ·

🎜X개의 요청(1개, 수십, 수천 등)이 처리되면 PHP는 마침내 자체 종료되고 종료됩니다. PHP 프로세스를 종료하는 것을 모듈 종료 단계라고 합니다. 약어는 MSHUTDOWN입니다. 🎜🎜이러한 단계를 그릴 수 있으면 다음 메시지가 표시될 수 있습니다. 🎜🎜PHP 수명주기 살펴보기🎜

병렬 모델

🎜CLI 환경에서는 모든 것이 쉽습니다. 프로세스가 요청을 처리합니다. 별도의 PHP 스크립트를 시작하고 끝납니다. . CLI 환경은 웹 환경의 전문화이며 더 복잡합니다. 🎜🎜여러 요청을 동시에 처리하려면 병렬 모델을 실행해야 합니다. PHP에는 두 가지 유형이 있습니다: 🎜
  • 프로세스 기반 모델
  • 스레드 기반 모델
🎜 프로세스 모델을 사용하면 운영 체제가 각 모델을 격리합니다. PHP 인터프리터를 자체 프로세스로 통합합니다. 이 모델은 Unix에서 매우 일반적입니다. 각 요청은 자체 프로세스로 이동합니다. PHP-CLI, PHP-FPM 및 PHP-CGI가 이 모델을 사용합니다. 🎜🎜스레드 기반 모델에서 각 PHP 인터프리터는 스레드 라이브러리를 사용하여 스레드로 격리됩니다. 이 모델은 주로 Windows 운영 체제에서 사용되지만 대부분의 Unix에서도 사용할 수 있습니다. ZTS 모드로 구축하려면 PHP 및 해당 확장이 필요합니다. 🎜🎜이것은 프로세스 기반 모델입니다: 🎜🎜../. . /_images/php_lifetime_process.png🎜🎜이것은 스레드 기반 모델입니다: 🎜🎜PHP 수명주기 살펴보기🎜
🎜Note🎜🎜확장 개발자로서 PHP의 다중 프로세스 모듈은 선택 사항이 아닙니다. 당신은 그것을 지원해야합니다. 스레드 환경, 특히 Windows에서 확장을 실행하려면 확장을 활성화하고 이에 대해 프로그래밍해야 합니다. 🎜

PHP 확장 후크

🎜 짐작할 수 있듯이 PHP 엔진은 여러 수명 주기 지점에서 확장을 트리거합니다. 우리는 이것을후크 함수 🎜라고 부릅니다. 확장 프로그램은 엔진에 등록할 때 함수 후크를 선언하여 특정 수명 주기 지점에 대한 관심을 선언할 수 있습니다.
이러한 후크는 PHP 확장 구조(zend_module_entry 구조)를 분석할 때 명확하게 볼 수 있습니다. 🎜rrreee🎜이제 이 후크에 어떤 종류의 코드를 작성해야 하는지 살펴보겠습니다. 🎜

모듈 초기화: MINIT()

🎜PHP 프로세스 시작 단계입니다. 확장된 MINIT()에서는 각 후속 요청에 필요한 영구 개체나 정보를 로드하고 할당합니다. 대부분은 읽기 전용 개체로 할당됩니다. 🎜

MINIT()에서는 아직 스레드나 프로세스가 나타나지 않았으므로 아무런 보호 없이 전역 변수에 대한 전체 액세스 권한을 갖습니다. 또한 요청이 아직 시작되지 않았으므로 요청 바인딩된 메모리를 할당할 수 없습니다. MINIT() 단계에서는 Zend 메모리 관리 할당을 사용하지 않지만 영구 할당이 사용됩니다. emaloc()이 아니라 pemalloc()입니다. 그렇지 않으면 충돌이 발생합니다. MINIT()中,尚未有线程或进程弹出,所以你完全可以访问全局变量,而没有任何保护。另外,由于请求尚未启动,因此你不能分配请求绑定的内存。你永远不会在MINIT()步骤中使用Zend 内存管理 分配,但是会使用永久分配。不是 emalloc(),而是pemalloc()。否则会导致崩溃。

在 MINIT()中,执行引擎仍未启动,所以不要在没有特别注意的情况下,尝试访问其任何结构。

如果你需要为你的扩展注册 INI 入口,则MINIT() 是正确的做法。

如果你要为以后使用而注册只读zend_strings,请使用持久分配了。

如果你需要分配的对象在处理请求时会写入,那么你必须复制它们的内存分配到该请求的线程专用池。记住,你只可以在MINIT()中安全地写入全局空间。

注意

内存管理、分配和调试是内存管理的部分章节。

在 php_module_startup()函数中,通过zend_startup_modules()触发 MINIT()

模块终止:MSHUTDOWN()

这是 PHP 进程终止步骤。很容易, 基本上,你在这里运行了与MINIT()中使用的相反的操作。你释放了资源,取消 INI 设置的注册等等。

再次注意:执行引擎是关闭的,所以你不应在此处访问其任何变量。

由于你在此处不需要请求,所以不应使用Zend 内存管理 的efree() 或类似函数去释放资源,但对于释放持久分配,使用pefree()

 在php_module_shutdown()函数中,由zend_shutdown()zend_destroy_modules()中触发MSHUTDOWN()

请求初始化: RINIT()

刚刚看过的请求,PHP 将在这里处理它。在RINIT()中,你引导了处理该精确请求所需的资源。PHP 是一种无共享架构,它提供了内存管理功能。

在 RINIT()中,如果需要分配动态内存,你将使用Zend 内存管理器。你将调用 emalloc()。Zend 内存管理器 追踪你通过它分配的内存,当请求关闭时,如果你忘记这么做,它将尝试释放请求绑定的内存(你不应这么做)。

在这里,你不应请求持久的动态内存,即 libc 的malloc() 或Zend 的pemalloc()。如果你在这里请求持久内存,并且忘记释放它,则将造成泄露,并且随着 PHP 处理越来越多的请求而堆积,最终导致进程崩溃(Kernel OOM) ,并且导致机器内存不足。

另外,务必注意不要在这里写入全局空间。如果 PHP 作为选定的并行模型运行到线程中,那么你将修改每个线程池中的上下文(所有与你的请求并行处理的请求),并且如果你没有锁定内存,也可能触发竞争条件。如果你需要全局,你必须保护它们。

注意

全局范围管理解释在专用章节。

在php_request_startup()函数中,通过zend_activate_module()触发RINIT()

请求终止: RSHUTDOWN()

这是 PHP 请求终止步骤。PHP 刚结束处理其请求,现在来清理其部分作为无共享架构的内存。接下来的请求不应记住当前请求的任何内容。很容易,基本上,你在此处执行了与RINIT()使用的相反的操作。你释放了请求绑定的资源。

由于你在此处使用了请求,你应使用 Zend 内存管理器的efree()或类似方式释放资源。如果你忘记释放并且造成泄露,在调试版本下,内存管理器将在进程stderr上记录关于泄露的指针的日记,并且将为你释放它们。

给你个主意,RSHUTDOWN()将被调用:

  • 执行用户区关闭功能后 (register_shutdown_function())
  • 在调用每个对象析构函数之后
  • PHP 输出缓冲区刷新之后
  • 禁用 max_execution_time 之后

在php_request_shutdown()函数中,通过zend_deactivate_modules()触发RSHUTDOWN()

Post 请求终止: PRSHUTDOWN()

这个钩子很少使用。它在 RSHUTDOWN()之后调用,但是中间还会运行一些额外的引擎代码。
尤其是在 Post-RSHUTDOWN 中:

  • PHP 输出缓冲区已关闭,并且它的处理程序已刷新
  • PHP 超全局已经销毁
  • 执行引擎已经关闭

这个钩子很少使用。在php_request_shutdown()函数中,通过zend_post_deactivate_modules(),在RSHUTDOWN()

MINIT()에서는 실행 엔진이 아직 시작되지 않았으므로 특별한 주의 없이 해당 구조에 액세스하려고 시도하지 마세요. 🎜🎜확장 프로그램에 대한 INI 항목을 등록해야 하는 경우 MINIT()가 올바른 접근 방식입니다. 🎜🎜나중에 사용하기 위해 읽기 전용 zend_string을 등록하려면 영구 할당을 사용하세요. 🎜🎜요청을 처리하는 동안 할당해야 하는 개체가 기록되는 경우 해당 요청에 대한 스레드별 풀에 해당 메모리 할당을 복사해야 합니다. MINIT() 내의 전역 공간에만 안전하게 쓸 수 있다는 점을 기억하세요. 🎜
🎜Note🎜🎜메모리 관리, 할당 및 디버깅은 메모리 관리 장의 일부입니다. 🎜
🎜php_module_startup() 함수에서 zend_startup_modules()를 통해 MINIT()를 트리거합니다. 🎜

모듈 종료: MSHUTDOWN()

🎜PHP 프로세스 종료 단계입니다. 기본적으로 MINIT()에서 사용한 것과 반대로 실행하는 것은 쉽습니다. 리소스를 확보하고 INI 설정 등록을 취소하는 등의 작업을 수행합니다. 🎜🎜다시 한 번 참고하세요. 실행 엔진이 꺼져 있으므로 여기에서 해당 변수에 액세스하면 안 됩니다. 🎜🎜여기에서는 요청이 필요하지 않으므로 Zend Memory Management의 efree() 또는 이와 유사한 기능을 사용하여 리소스를 해제하면 안 되지만, 지속적인 할당을 해제하려면 pefree()를 사용하세요. 코드>. 🎜🎜 php_module_shutdown() 함수에서 zend_shutdown()zend_destroy_modules()에 의해 MSHUTDOWN()이 트리거됩니다. 🎜

요청 초기화: RINIT()

🎜방금 본 요청은 PHP가 여기서 처리합니다. RINIT()에서는 정확한 요청을 처리하는 데 필요한 리소스를 지시합니다. PHP는 메모리 관리 기능을 제공하는 비공유 아키텍처입니다. 🎜🎜RINIT()에서 동적 메모리를 할당해야 하는 경우 Zend 메모리 관리자를 사용합니다. emaloc()을 호출합니다. Zend 메모리 관리자는 이를 통해 할당된 메모리를 추적하고, 요청이 닫힐 때 이 작업을 잊어버린 경우 요청 바인딩된 메모리를 해제하려고 시도합니다(해선 안 됨). 🎜🎜여기서는 libc의 malloc() 또는 Zend의 pemalloc()과 같은 영구 동적 메모리를 요청하면 안 됩니다. 여기에서 영구 메모리를 요청하고 해제하는 것을 잊어버리면 PHP가 점점 더 많은 요청을 처리함에 따라 누수가 발생하여 결국 프로세스가 중단되고(커널 OOM) 시스템에 메모리가 부족해지게 됩니다. 🎜🎜또한 여기 글로벌 공간에 글을 쓰지 않도록 주의하세요. PHP가 선택된 병렬 모델로 스레드에서 실행되면 각 스레드 풀의 컨텍스트(모든 요청이 병렬로 처리됨)를 수정하게 되며, 메모리를 잠그지 않으면 경쟁 조건이 발생할 수도 있습니다. 큰 그림을 원한다면 그들을 보호해야 합니다. 🎜
🎜Note🎜🎜전역 범위 관리는 해당 섹션에서 설명합니다. 🎜
🎜php_request_startup() 함수에서 zend_activate_module()을 통해 RINIT()를 트리거합니다. 🎜

해지 요청: RSHUTDOWN()

🎜PHP 요청 종료 단계입니다. PHP는 방금 요청 처리를 마쳤으며 이제 비공유 아키텍처로 메모리 부분을 정리할 시간입니다. 후속 요청은 현재 요청의 어떤 것도 기억해서는 안 됩니다. 기본적으로 여기서 RINIT()가 사용하는 것과 반대되는 작업을 수행하는 것은 쉽습니다. 요청에 의해 바인딩된 리소스를 해제합니다. 🎜🎜여기서 요청을 사용하고 있으므로 Zend 메모리 관리자의 efree() 또는 이와 유사한 것을 사용하여 리소스를 해제해야 합니다. 해제하는 것을 잊고 누수를 일으키는 경우 디버그 빌드에서 메모리 관리자는 누수된 포인터를 프로세스의 stderr에 기록하고 이를 해제합니다. 🎜🎜아이디어를 제공하기 위해 RSHUTDOWN()이 호출됩니다: 🎜
  • 사용자 영역 종료 기능을 실행한 후(register_shutdown_function()) li>
  • 각 객체의 소멸자를 호출한 후
  • PHP 출력 버퍼가 플러시된 후
  • max_execution_time을 비활성화한 후
🎜php_request_shutdown()에서 함수를 사용하면 zend_deactivate_modules()를 통해 RSHUTDOWN()을 트리거합니다. 🎜

포스트 요청 종료: PRSHUTDOWN()

🎜이 후크는 거의 사용되지 않습니다. RSHUTDOWN() 이후에 호출되지만 중간에 일부 추가 엔진 코드가 실행됩니다.
특히 RSHUTDOWN 이후: 🎜
  • PHP 출력 버퍼가 닫히고 해당 핸들러가 플러시되었습니다.
  • PHP 슈퍼 전역이 파괴되었습니다.
  • 실행 엔진이 정지되었습니다
🎜이 후크는 거의 사용되지 않습니다. php_request_shutdown() 함수에서는 zend_post_deactivate_modules()를 통해 RSHUTDOWN() 이후에 트리거됩니다. 🎜

전역 초기화: GINIT()

스레드 라이브러리는 스레드가 나타날 때마다 이 후크를 호출합니다. 여러 프로세스를 사용하는 경우 PHP가 시작될 때 MINIT()가 실행되기 직전에 이 함수를 호출하세요. MINIT() 之前调用此函数。

这里不讲太多细节,只需在这里简单地初始化全局变量,通常初始化为0。全局管理将在专用章节详细说明。

记住,全局变量不会在每次请求后清理。如果你需要为每次新的请求重置它们(可能),那么你必须将这样地进程放到RINIT()中。

注意

全局范围管理在专用章节详细介绍。

全局终止: GSHUTDOWN()

在线程库中,每当线程终止时都会调用该钩子。如果你使用多线程,该函数将在 PHP 终止期间(在MSHUTDOWN())被调用一次。

在这里不提供太多细节,你只需简单地在这里取消初始化你的全局变量,通常你不必做什么,但如果在构建全局(GINIT())时分配了资源,在这里的步骤你应该释放它们。

全局管理将在专用章节详细介绍。

记住,全局变量在每次请求后不会清除。即GSHUTDOWN()不会作为RSHUTDOWN()的一部分被调用。

注意

全局范围管理在专用章节有详细介绍。

信息收集: MINFO()

该钩子很特殊,它永远不会被引擎自动触发,只有你询问它有关扩展的信息时才会触发。典型的例子是调用phpinfo()。然后运行此函数,并将有关当前扩展的特殊信息打印到流中。

简而言之,phpinfo() 展示信息。

该函数也可以通过 CLI 使用反射开关之一调用,例如php --ri pib 或通过用户区调用ini_get_all()

你可以将其留空,在这种情况下,只有扩展的名字显示,没有其他(可能不会显示 INI 设置,因为这是 MINFO() 的一部分)。

关于 PHP 生命周期的思考

PHP 수명주기 살펴보기

你可能已经发现了,RINIT() 和 RSHUTDOWN() 尤其重要,因为它们在扩展中被触发成千上万次。如果 PHP 步骤是关于 Web (不是 CLI),并且已经配置为可以处理无数次请求,那么你的 RINIT()/RSHUTDOWN() 组将被无数次调用。

我们想要再次引起你对内存管理的关注。在处理请求时(在RINIT() 和 RSHUTDOWN()之间),你最终泄露的小字节,将对满载服务器产生严重影响。这就是为什么建议你使用 Zend 内存管理器 进行此类分配,并且准备好调试内存布局。作为无共享架构的一部分,PHP 在每次请求最后都会忘记并释放请求内存,这是 PHP 的内部设计。

另外,如果你的崩溃信号是 SIGSEGV (坏内存访问),则整个进程会崩溃。如果 PHP 是使用线程作为多进程引擎,那么你所有其他线程也将崩溃,甚至可能造成服务器崩溃。

注意

C 语言不是 PHP 语言。使用 C,在程序的错误很可能导致程序的崩溃与终止。

通过重写函数指针进行挂钩

现在你知道引擎何时会触发代码,还存在值得注意的函数指针,你可以替换它们来挂载到引擎。因为那些指针是全局变量,因此你可以将它们替换为 MINIT() 步骤,并将它们放回MSHUTDOWN()

여기서 너무 자세히 설명하지 않고 여기서 전역 변수를 초기화하기만 하면 됩니다. 일반적으로 0으로 초기화됩니다. 글로벌 경영에 대해서는 해당 장에서 자세히 설명하겠습니다.

모든 요청 후에 전역 변수가 정리되지 않는다는 점을 기억하세요. 새로운 요청이 있을 때마다 이를 재설정해야 하는 경우에는 해당 프로세스를 RINIT()에 넣어야 합니다.
  • Note

    전역 범위 관리는 해당 장에 자세히 설명되어 있습니다.
    • 전역 종료: GSHUTDOWN()스레드 라이브러리에서 이 후크는 스레드가 종료될 때마다 호출됩니다. 멀티스레딩을 사용하는 경우 이 함수는 PHP 종료 중에 MSHUTDOWN()에서 한 번 호출됩니다. 여기에 너무 많은 세부 정보를 제공하지 않고 여기서 전역 변수를 간단히 초기화 해제할 수 있습니다. 일반적으로 아무 작업도 수행할 필요가 없지만 전역(GINIT()) 리소스를 빌드할 때 할당된 경우 이 단계에서는 해당 항목을 해제해야 합니다.
    글로벌 경영에 대해서는 해당 장에서 자세히 소개하겠습니다.
  • 각 요청 후에 전역 변수가 지워지지 않는다는 점을 기억하세요. 즉, GSHUTDOWN()RSHUTDOWN()의 일부로 호출되지 않습니다.

    Note
    • 전역 범위 관리는 해당 장에서 자세히 소개됩니다.
  • 정보 수집: MINFO()이 후크는 매우 특별합니다. 엔진에 의해 자동으로 트리거되지 않으며 확장에 대한 정보를 요청할 때만 트리거됩니다. 일반적인 예는 phpinfo()를 호출하는 것입니다. 그런 다음 이 함수가 실행되고 현재 확장에 대한 특별 정보가 스트림에 인쇄됩니다.
  • 간단히 말하면 phpinfo()는 정보를 표시합니다. 이 함수는 php --ri pib와 같은 리플렉션 스위치 중 하나를 사용하거나 사용자 영역 호출 ini_get_all()을 통해 CLI를 통해 호출할 수도 있습니다. 비워둘 수 있습니다. 이 경우 확장 이름만 표시되고 다른 것은 표시되지 않습니다(INI 설정은 MINFO()의 일부이므로 표시되지 않을 수 있음). PHP 수명 주기에 대한 생각
  • ../../ _images/php_extensions_lifecycle.png
  • RINIT()RSHUTDOWN()은 수천 개의 확장 프로그램에서 수천 번 트리거되기 때문에 특히 중요하다는 점을 눈치채셨을 것입니다. 타임스. PHP 단계가 웹용(CLI 아님)이고 무한한 수의 요청을 처리하도록 구성된 경우 RINIT()/RSHUTDOWN() 그룹은 무한히 호출됩니다.

    메모리 관리에 대해 다시 한번 주목해 드리고자 합니다. 요청을 처리할 때(RINIT()RSHUTDOWN() 사이) 결국 완전히 로드된 서버에 심각한 영향을 줄 수 있는 작은 바이트가 누출됩니다. 그렇기 때문에 이러한 할당에 Zend 메모리 관리자를 사용하고 메모리 레이아웃을 디버깅할 준비를 하는 것이 좋습니다. 비공유 아키텍처의 일부로, PHP는 요청이 끝날 때마다 요청된 메모리를 잊어버리고 해제합니다. 이는 PHP의 내부 설계에 따른 것입니다.
    • 또한 충돌 신호가 SIGSEGV(잘못된 메모리 액세스)인 경우 전체 프로세스가 충돌합니다. PHP가 스레드를 다중 프로세스 엔진으로 사용하는 경우 다른 모든 스레드도 충돌하며 서버가 충돌할 수도 있습니다.
      NoteC 언어는 PHP 언어가 아닙니다. C를 사용하면 프로그램 오류로 인해 프로그램이 충돌하고 종료될 가능성이 높습니다.
  • 함수 포인터를 재정의하여 후킹

  • 이제 엔진이 코드를 트리거할 시기를 알았으므로 엔진에 후크하기 위해 교체할 수 있는 주목할 만한 함수 포인터도 있습니다. 이러한 포인터는 전역 변수이므로 MINIT() 단계로 바꾸고 MSHUTDOWN()에 다시 넣을 수 있습니다. 관심 있는 대상은 다음과 같습니다:
  • AST, Zend/zend_ast.h:
  • void (
      zend_ast_process_t)(zend_ast
    • ast)
  • Compiler, Zend/zend_ compile. h:

    • zend_op_array (zend_compile_file)(zend_file_handle
    • file_handle, int 유형)*
    • zend_op_array
    • (
    zend_compile_string)(zval
  • source_string, char
  • filename)

    • 실행자, Zend/zend_execute.h:
    void(
  • zend_execute_ex)(zend_execute_data
  • execute_data)

    🎜🎜void(🎜zend_execute_internal)(zend_execute_data 🎜execute_data, zval 🎜return_value)*🎜🎜🎜🎜 🎜GC, d/zend_gc.h:🎜🎜🎜🎜int ( 🎜 gc_collect_cycles)(void)*🎜🎜🎜🎜🎜TSRM, TSRM/TSRM.h:🎜🎜🎜🎜void (🎜tsrm_thread_begin_func_t)(THREAD_T thread_id)*🎜🎜🎜void (🎜tsrm_th read_end_func_t) (THREAD_T 스레드_ID)*🎜🎜🎜 🎜🎜Error, Zend/zend.h:🎜🎜🎜🎜void (🎜zend_error_cb)(int type, const char 🎜error_filename, const uint error_lineno, const char 🎜format, va_list args)*🎜🎜🎜🎜🎜예외, Zen d / zend_Exceptions.h:🎜
    • void (zend_throw_Exception_hook)(zval ex)
  • Lifetime, Zend/zend.h:

    • void (zend_on_timeout)(int 초)*
    • void(zend_interrupt_function)( zend_execute_data execute_data)
    • void (zend_ticks_function)(int 진드기)*
  • 다른 것들도 있지만 위의 내용은 PHP 확장을 디자인할 때 필요할 수 있는 가장 중요한 것입니다. 이름은 읽기 쉬우므로 자세히 설명하지 않겠습니다.

    더 많은 정보가 필요하면 PHP 소스 코드를 살펴보고 이를 트리거하는 시기와 방법을 알아볼 수 있습니다.

    위 내용은 PHP 수명주기 살펴보기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제