[ PHP 内核与扩展开发系列] PHP 启动与终止那点事:一次请求的生命周期

栏目: PHP · 发布时间: 6年前

内容简介:[ PHP 内核与扩展开发系列] PHP 启动与终止那点事:一次请求的生命周期

在前面的章节里,你已经学会了如何使用 MINIT 函数在 PHP 加载模块的共享库时来执行初始化任务。在第一章,你还了解到扩展里其他三个函数:和 MINIT 函数对应的 MSHUTDOWN 函数,以及在每个页面请求开始和结束时候调用的方法 —— RINIT 函数和 RSHUTDOWN 函数。

除了上面说到的四个函数,还有两个函数只用于处理单个线程的启动和关闭,它们只作用于线程环境。

回顾一下新增一个基本扩展时,我们在扩展目录下创建如下几个源文件:

config.m4

PHP_ARG_ENABLE(sample4,
    [Whether to enable the "sample4" extension],
    [ enable-sample4 Enable "sample4" extension support])
if test $PHP_SAMPLE4 != "no"; then
    PHP_SUBST(SAMPLE4_SHARED_LIBADD)
    PHP_NEW_EXTENSION(sample4, sample4.c, $ext_shared)
fi

php_sample4.h

#ifndef PHP_SAMPLE4_H
/* 避免重复引入 */
#define PHP_SAMPLE4_H

/* 定义扩展属性 */
#define PHP_SAMPLE4_EXTNAME
#define PHP_SAMPLE4_EXTVER

/* 在 PHP 源码树之外构建时导入配置项 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* 引入 PHP 标准头 */
#include "php.h"

/* 定义 Zend 在加载扩展时使用的入口标志
 */
extern zend_module_entry sample4_module_entry;
#define phpext_sample4_ptr &sample4_module_entry
#endif /* PHP_SAMPLE4_H */

sample4.c

#include "php_sample4.h"
#include "ext/standard/info.h"

static function_entry php_sample4_functions[] = {
    { NULL, NULL, NULL }
};

PHP_MINIT_FUNCTION(sample4)
{
    return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(sample4) {
    return SUCCESS;
}

PHP_RINIT_FUNCTION(sample4) {
    return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(sample4) {
    return SUCCESS;
}

PHP_MINFO_FUNCTION(sample4) {
}

zend_module_entry sample4_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    PHP_SAMPLE4_EXTNAME,
    php_sample4_functions,
    PHP_MINIT(sample4),
    PHP_MSHUTDOWN(sample4),
    PHP_RINIT(sample4),
    PHP_RSHUTDOWN(sample4),
    PHP_MINFO(sample4),
#if ZEND_MODULE_API_NO >= 20010901
    PHP_SAMPLE4_EXTVER,
#endif
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_SAMPLE4
    ZEND_GET_MODULE(sample4)
#endif

注意:每个启动或者关闭的方法在 return SUCCESS 时退出。如果其中任何函数 return FAILURE ,那么 PHP 会为了避免出现严重问题而将请求中止。

现在你应该对 MINIT 很熟悉了吧,它会在一个模块第一次加载到进程空间的时候被触发。

对于多进程的 SAPI(Apache1 & Apache2-prefork),多个 Web server 进程会 fork 出多个 mod_php 实例。每个 mod_php 实例都必须加载属于这个实例的扩展模块,这意味着 MINIT 函数会被执行多次。但是,它在每个进程空间中只会执行一次。

当一个模块被卸载, MSHUTDOWN 会被调用,它可以使用该模块的任何资源,比如被占用的内存可能会被释放。

这里要注意一个特性, 某些 PHP 的 SAPI 中, 比如 Apache Prefork, PHP 是作为一个动态库被加载到 Apache 中的, 而从 Apache 1.3 以后(如果我没记错的话), Apache 做了一个优化, 优化的结果就是首先执行各个动态模块的模块初始化工作, 然后才做 fork, 派生 worker 子进程, 所以反映到这里, 有的时候会出现 MINIT 只执行一次, 而 MSHUTDOWN 会执行多次的现象。

理论上来说,你可以在 MSHUTDOWN 中跳过一些资源的清理工作,然而在 APACHE 1.3 中,你会发现一个有趣的事情,Apache 会载入 mod_php ,并且会执行所有的 MINIT 方法,然后立刻卸载 mod_php 来触发 MSHUTDOWN ,接着再次装入,在没有执行 MSHUTDOWN 的时候,最初使用 MINIT 加载的资源将被泄露和浪费。

在多线程的 SAPI 中,有时需要为每个线程分配自己独立的资源或跟踪每个请求的计数器。对于这些特殊情况,在每一个线程钩子中,允许额外的启动和关闭要执行的方法。通常情况下,当多进程的 SAPI(Apache2-worker)启动时,它会创建出十几个或者更多的线程,以便能够处理多个并发请求。

任何可以在请求之间共享,但不能由多个线程在同一进程空间同时访问的资源,通常分配在线程的构造和析构方法中以免发生冲突。比如可能包括在 EG(persistent_list) HashTable 中的持久性资源,因为他们往往​​包括网络或文件资源。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Practical Vim, Second Edition

Practical Vim, Second Edition

Drew Neil / The Pragmatic Bookshelf / 2015-10-31 / USD 29.00

Vim is a fast and efficient text editor that will make you a faster and more efficient developer. It’s available on almost every OS, and if you master the techniques in this book, you’ll never need an......一起来看看 《Practical Vim, Second Edition》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换