php教程 php手册 [转]PHP的执行流程,PHP扩展加载过程 - orlion

[转]PHP的执行流程,PHP扩展加载过程 - orlion

May 20, 2016 am 10:14 AM

原文:http://www.imsiren.com/archives/535

为了以后能开发PHP扩展..就一定要了解PHP的执行顺序..这篇文章就是为C开发PHP扩展做铺垫.
web环境 我们假设为 apache.
在编译PHP的时候,为了能够让Apache支持PHP,我们会生成一个mod_php5.so的模块.apache加载这个模块..
在url访问.php文件的时候就会转给mod_php5.so模块来处理.这个玩意是什么..就是我们常说的SAPI
英文名字是:Server abstraction API.
SAPI说的其实是一个统称,其下有 ISAPI,CLI SAPI, CGI等.
有了它,就可以很容易的跟其他东西交互.比如APACHE,IIS,CGI等.
好了回到正题.
apache启动后会将mod_pho5.so模块的hook handler注册进来.apache今天不是主角,所以不细说.
当APACHE检测到 访问的url是一个php文件时,这时候就会把控制权交给sapi.

如下图:

进入到sapi后,首先会执行sapi/apache/mod_php5.c 文件的php_init_handler函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void php_init_handler(server_rec *s, pool *p)
{
        register_cleanup(p, NULL, (void (*)(void *))apache_php_module_shutdown_wrapper, (void (*)(void *))php_module_shutdown_for_exec);
        if (!apache_php_initialized) {
                apache_php_initialized = 1;
#ifdef ZTS
                tsrm_startup(1, 1, 0, NULL);
#endif
                sapi_startup(&apache_sapi_module);
                php_apache_startup(&apache_sapi_module);
        }
#if MODULE_MAGIC_NUMBER >= 19980527
        {
                TSRMLS_FETCH();
                if (PG(expose_php)) {
                        ap_add_version_component("PHP/" PHP_VERSION);
                }
        }
#endif
}

该函数主要调用 两个函数
sapi_startup(&apache_sapi_module);
php_apache_startup(&apache_sapi_module);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SAPI_API void sapi_startup(sapi_module_struct *sf)
{
        sf->ini_entries = NULL;
        sapi_module = *sf;
 
.................
        sapi_globals_ctor(&sapi_globals);
................
 
        virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
 
..................
 
        reentrancy_startup();
}

sapi_startup创建一个 sapi_globals_struct结构体.
sapi_globals_struct保存了apache请求的基本信息,如服务器信息,header,编码等.

1
2
3
4
5
6
static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
{
        memset(sapi_globals, 0, sizeof(*sapi_globals));
        zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
        php_setup_sapi_content_types(TSRMLS_C);
}

known_post_content_types是一个HashTable,将其大小初始化为5.从字面意义上我猜测它保存的应该是客户端传递过来的内容类型.
php_setup_sapi_content_types函数将sapi_post_entry添加到sapi_globals里
sapi_startup执行完毕后再执行php_apache_startup

1
2
3
4
5
6
7
8
static int php_apache_startup(sapi_module_struct *sapi_module)
{
        if (php_module_startup(sapi_module, &apache_module_entry, 1) == FAILURE) {
                return FAILURE;
        } else {
                return SUCCESS;
        }
}

php_module_startup 内容太多..是介绍一下作用.
1. 初始化zend_utility_functions 结构.这个结构是设置zend的函数指针,比如错误处理函数,输出函数,流操作函数等.
2. 设置环境变量.
3. 加载php.ini配置.
4. 加载php内置扩展.
5. 写日志.
6. 注册php内部函数集.
7. 调用 php_ini_register_extensions,加载所有外部扩展
8. 开启所有扩展
9. 一些清理操作.
重点说一下 3,4,7,8
加载php.ini配置
if (php_init_config(TSRMLS_C) == FAILURE) {
return FAILURE;
}
php_init_config函数会在这里检查所有php.ini配置,并且找到所有加载的模块,添加到php_extension_lists结构中.
加载php内置扩展
调用 zend_register_standard_ini_entries加载所有php的内置扩展,如array,mysql等.
调用 php_ini_register_extensions,加载所有外部扩展
main/php_ini.c

1
2
3
4
5
6
7
8
void php_ini_register_extensions(TSRMLS_D)
{
        zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC);
        zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb TSRMLS_CC);
 
        zend_llist_destroy(&extension_lists.engine);
        zend_llist_destroy(&extension_lists.functions);
}

zend_llist_apply函数遍历extension_lists 执行会掉函数 php_load_php_extension_cb
php_load_php_extension_cb

1
2
3
4
static void php_load_zend_extension_cb(void *arg TSRMLS_DC)
{
        zend_load_extension(*((char **) arg));
}

调用 ext/standard/dl.c zend_load_extension 加载扩展,
该函数略过..
该函数最后调用
if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) {
DL_UNLOAD(handle);
return FAILURE;
}
将 扩展信息 放到 Hash表module_registry中
Zend/zend_API.c

1
2
3
4
5
if (zend_hash_add(&module_registry, lcname, name_len+1, (void *)module, sizeof(zend_module_entry), (void**)&module_ptr)==FAILURE) {
                zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name);
                efree(lcname);
                return NULL;
}

最后
zend_startup_modules(TSRMLS_C); //对模块进行排序,并检测是否注册到module_registry HASH表里

zend_startup_extensions(); //执行extension->startup(extension);启动扩展…

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

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)