sapi_module_struct 研究(一)
来源:互联网 发布:fanuc编程软件 编辑:程序博客网 时间:2024/06/18 00:42
今日研究了PHP中的sapi_module_struct结构体。众所周知,PHP_CLI中先include了SAPI.h。先列出这个著名的stuct。 琢磨虽一无是用,但人生本有何用?
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_DEBUGif (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));}#endifif (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()
/* {{{ 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 ZTSzend_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_WIN32php_os = "WINNT";#if _MSC_VER >= 1400old_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#elsephp_os=PHP_OS;#endif#ifdef ZTStsrm_ls = ts_resource(0);#endif#ifdef PHP_WIN32php_win32_init_rng_lock();#endifmodule_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不用关心底层的具体实现。
0 0
- sapi_module_struct 研究(一)
- php内核分析(一)-sapi_module_struct
- php内核分析1 sapi_module_struct
- JSP研究(一)
- RunUO代码研究(一)
- petshop4.0研究(一)
- petshop4.0研究(一)
- NHibernate 系列研究[一]
- Duwamish7的研究(一)
- Spring2.0研究(一)
- 怎样做研究 一
- TinyLine研究(一)
- IAGO研究(一)
- NHibernate 系列研究[一]
- 怎样做研究 一
- BotNet 研究笔记一
- FCKEditor研究一
- spring研究【一】
- cocos2d-x 进度条实现(被砍)掉血效果
- Linux命令大观
- C/C++高阶语法:函数指针及其应用
- 避免用char类型作为数组小标
- hdu 5532 Almost Sorted Array
- sapi_module_struct 研究(一)
- LeetCode:Rectangle Area
- Lesson 6 Transposition and conjugation
- PHP怎么与C语言通信
- OC第五天之 Dictionary NSSet 数组排序
- c++中的引用和指针
- ACM之括号匹配(二)
- 2015年09月北戴河之旅
- scala使用redis client - Jedis