sapi_module_struct 研究(一)
2015-11-02 21:03
225 查看
今日研究了PHP中的sapi_module_struct结构体。众所周知,PHP_CLI中先include了SAPI.h。先列出这个著名的stuct。 琢磨虽一无是用,但人生本有何用?
这个cli_sapi_module在main函数中将地址交给了sapi_module指针变量:
因而,在CLI主函数内,这个sapi_module指针被送入php_module_startup等上层进行启动。在这里进入了启动过程:
然而在PHP_API/ZEND_API中,均使用了sapi_module.ub_write()访问成员函数,在命名中为什么要使用相同的变量名呢?容易搞晕。如下例:
这是因为,在SAPI.C文件中,定义了sapi_module这样一个全局变量:
这个变量在SAPI.h中被extern:
定义说明它不是指针类型,它在何处拥有了cli_sapi_module的成员呢?我猜估计在php_module_startup里,果然是:
自此以后,只要include "sapi.h"即可访问SAPI定义的函数。通过这种设计,成功的将不同SAPI的sapi_module送给同一个上层全局变量。使得上层handler不用关心底层的具体实现。
struct _sapi_module_struct { char *name; char *pretty_name; int (*startup)(struct _sapi_module_struct *sapi_module); int (*shutdown)(struct _sapi_module_struct *sapi_module); int (*activate)(TSRMLS_D); int (*deactivate)(TSRMLS_D); int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC); void (*flush)(void *server_context); struct stat *(*get_stat)(TSRMLS_D); char *(*getenv)(char *name, size_t name_len TSRMLS_DC); void (*sapi_error)(int type, const char *error_msg, ...); int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC); int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC); void (*send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC); int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC); char *(*read_cookies)(TSRMLS_D); void (*register_server_variables)(zval *track_vars_array TSRMLS_DC); void (*log_message)(char *message TSRMLS_DC); double (*get_request_time)(TSRMLS_D); void (*terminate_process)(TSRMLS_D); char *php_ini_path_override; void (*block_interruptions)(void); void (*unblock_interruptions)(void); void (*default_post_reader)(TSRMLS_D); void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC); char *executable_location; int php_ini_ignore; int php_ini_ignore_cwd; /* don't look for php.ini in the current directory */ int (*get_fd)(int *fd TSRMLS_DC); int (*force_http_10)(TSRMLS_D); int (*get_target_uid)(uid_t * TSRMLS_DC); int (*get_target_gid)(gid_t * TSRMLS_DC); unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); void (*ini_defaults)(HashTable *configuration_hash); int phpinfo_as_text; char *ini_entries; const zend_function_entry *additional_functions; unsigned int (*input_filter_init)(TSRMLS_D); };上面结构体给出了sapi_module_struct定义。在CLI作为SAPI入口的内核的启动过程中,至少创建了这样的一个实例:
static sapi_module_struct cli_sapi_module = { "cli", /* name */ "Command Line Interface", /* pretty name */ php_cli_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ NULL, /* activate */ sapi_cli_deactivate, /* deactivate */ sapi_cli_ub_write, /* unbuffered write */ sapi_cli_flush, /* flush */ NULL, /* get uid */ NULL, /* getenv */ php_error, /* error handler */ sapi_cli_header_handler, /* header handler */ sapi_cli_send_headers, /* send headers handler */ sapi_cli_send_header, /* send header handler */ NULL, /* read POST data */ sapi_cli_read_cookies, /* read Cookies */ sapi_cli_register_variables, /* register server variables */ sapi_cli_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES };
这个cli_sapi_module在main函数中将地址交给了sapi_module指针变量:
sapi_module_struct *sapi_module = &cli_sapi_module;
因而,在CLI主函数内,这个sapi_module指针被送入php_module_startup等上层进行启动。在这里进入了启动过程:
if (sapi_module->startup(sapi_module) == FAILURE) { /* there is no way to see if we must call zend_ini_deactivate() * since we cannot check if EG(ini_directives) has been initialised * because the executor's constructor does not set initialize it. * Apart from that there seems no need for zend_ini_deactivate() yet. * So we goto out_err.*/ exit_status = 1; goto out; }由于是指针,访问成员函数使用了 "->"。
然而在PHP_API/ZEND_API中,均使用了sapi_module.ub_write()访问成员函数,在命名中为什么要使用相同的变量名呢?容易搞晕。如下例:
/* {{{ int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC) * Unbuffered write */ PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC) { #if PHP_DEBUG if (len > UINT_MAX) { php_error(E_WARNING, "Attempt to output more than UINT_MAX bytes at once; " "output will be truncated %lu => %lu", (unsigned long) len, (unsigned long) (len % UINT_MAX)); } #endif if (OG(flags) & PHP_OUTPUT_DISABLED) { return 0; } if (OG(flags) & PHP_OUTPUT_ACTIVATED) { return sapi_module.ub_write(str, len TSRMLS_CC); } return php_output_direct(str, len); }
这是因为,在SAPI.C文件中,定义了sapi_module这样一个全局变量:
/* True globals (no need for thread safety) */ SAPI_API sapi_module_struct sapi_module;
这个变量在SAPI.h中被extern:
BEGIN_EXTERN_C() extern SAPI_API sapi_module_struct <strong>sapi_module</strong>; /* true global */ END_EXTERN_C()
定义说明它不是指针类型,它在何处拥有了cli_sapi_module的成员呢?我猜估计在php_module_startup里,果然是:
/* {{{ php_module_startup */ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules) { zend_utility_functions zuf; zend_utility_values zuv; int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */ char *php_os; zend_module_entry *module; #ifdef ZTS zend_executor_globals *executor_globals; void ***tsrm_ls; php_core_globals *core_globals; #endif #if defined(PHP_WIN32) || (defined(NETWARE) && defined(USE_WINSOCK)) WORD wVersionRequested = MAKEWORD(2, 0); WSADATA wsaData; #endif #ifdef PHP_WIN32 php_os = "WINNT"; #if _MSC_VER >= 1400 old_invalid_parameter_handler = _set_invalid_parameter_handler(dummy_invalid_parameter_handler); if (old_invalid_parameter_handler != NULL) { _set_invalid_parameter_handler(old_invalid_parameter_handler); } /* Disable the message box for assertions.*/ _CrtSetReportMode(_CRT_ASSERT, 0); #endif #else php_os=PHP_OS; #endif #ifdef ZTS tsrm_ls = ts_resource(0); #endif #ifdef PHP_WIN32 php_win32_init_rng_lock(); #endif module_shutdown = 0; module_startup = 1; sapi_initialize_empty_request(TSRMLS_C); sapi_activate(TSRMLS_C); if (module_initialized) { return SUCCESS; } sapi_module = *sf; php_output_startup(); // ......// }
自此以后,只要include "sapi.h"即可访问SAPI定义的函数。通过这种设计,成功的将不同SAPI的sapi_module送给同一个上层全局变量。使得上层handler不用关心底层的具体实现。
相关文章推荐
- 【LeetCode从零单刷】House Robber
- RCNN 安装编译与MATLAB2014下问题解决
- C#编程练习
- hdu 5532 Almost Sorted Array
- win7系统电脑机箱异常问题的解决方法
- 一次快速排序错误引发的思考
- 求排列的逆序数<归并><C++>
- listview 加载网络图片 item中上下有留白现象
- C/C++高阶语法:函数指针及其应用
- SELECTOR
- 软件文档的概念和细分
- TCP/IP实现以及常见问题
- 小电梯,学问大
- linux 基本操作笔记
- HDU 4027 Can you answer these queries?
- 【离散数学】实验三 偏序关系中盖住关系的求取及格论中有补格的判定
- 贾志鹏线性筛
- 我的电磁学讲义10:磁感应强度 毕奥-萨伐尔定律
- 【即时通讯】即时通讯及XMPP概述及…
- 【网络编程】Socket概念及简单聊天…