PHP-数据结构(SAPI)

在PHP生命周期的各个阶段,一些与服务相关的操作都是通过SAPI接口实现。这些内置实现的物理位置在PHP源码的SAPI目录。这个目录存放了PHP对各个服务器抽象层的代码,例如命令行程序的实现,Apache的mod_php模块实现以及fastcgi的实现等等。

SAPI分别在FPMCLI下是如何运行的?

SAPI

1
2
3
4
5
test.php
<?php
$temp = $_POST;
print_r($temp);
?>
  • FPM

    1
    2
    3
    4
    5
    6
    7
    8
    9
    static sapi_module_struct cgi_sapi_module = {
    "fpm_fcgi",
    ...
    sapi_cgibin_ub_write,
    sapi_cgibin_flush,
    ...
    sapi_cgi_read_post,
    ...
    };
  • CLI

    1
    2
    3
    4
    5
    6
    7
    8
    9
    static sapi_module_struct cgi_sapi_module = {
    "cli",
    ...
    sapi_cli_ub_write,
    sapi_cli_flush,
    ...
    NULL,
    ...
    };

sapi模块结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
struct _sapi_module_struct {
char *name;
char *pretty_name;

int (*startup)(struct _sapi_module_struct *sapi_module);//PHP被调用的时候,这个函数会被调用执行
int (*shutdown)(struct _sapi_module_struct *sapi_module);//PHP调用结束的时候,这个函数会被调用执行

int (*activate)(void);//每个request开始时会执行,进行一些初始化,资源分配的事务
int (*deactivate)(void);//每个request结束时会执行

size_t (*ub_write)(const char *str, size_t str_length);//这个hanlder告诉了Zend,如何输出数据,对于mod_php来说,这个函数提供了一个向response数据写的接口,而CLI只是简单的写到stdout
void (*flush)(void *server_context);//这个是提供给zend的刷新缓存的函数句柄,对于CLI来说,只是简单的调用系统提供的fflush;
zend_stat_t *(*get_stat)(void);//这部分用来让Zend可以验证一个要执行脚本文件的state,从而判断文件是否据有执行权限等等.
char *(*getenv)(char *name, size_t name_len);//为Zend提供了一个根据name来查找环境变量的接口,对于mod_php5来说,当我们在脚本中调用getenv的时候,就会间接的调用这个句柄.CLI和CGI很类似,直接调用父级是Shell, 所以,只是简单的调用了系统提供的genenv:

void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);//错误处理函数

int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers);//这个函数会在我们调用PHP的header()函数的时候被调用.
int (*send_headers)(sapi_headers_struct *sapi_headers);//这个函数会在要真正发送header的时候被调用,一般来说,就是当有任何的输出要发送之前:
void (*send_header)(sapi_header_struct *sapi_header, void *server_context);//这个用来单独发送每一个header

size_t (*read_post)(char *buffer, size_t count_bytes);//这个句柄指明了如何获取POST的数据,CLI是从stdin中读取POST DATA的,
char *(*read_cookies)(void);//这个句柄指明了如何获取cookies的数据

void (*register_server_variables)(zval *track_vars_array);//这个函数用以给$_SERVER变量中添加变量,CLI在此函数中注册了PHP_SELF,SCRIPT_FILENAME等server变量:
void (*log_message)(char *message, int syslog_type_int);//用来输出错误信息,对于CLI来说,只是简单的输出到stderr
double (*get_request_time)(void);//获取请求时间,只有apach2自定义了,默认为获取当前时间
void (*terminate_process)(void);//没有任何SAPI用到,无用代码

//STANDARD_SAPI_MODULE_PROPERTIES
char *php_ini_path_override;
void (*default_post_reader)(void);
void (*treat_data)(int arg, char *str, zval *destArray);
char *executable_location;
int php_ini_ignore;
int php_ini_ignore_cwd;
int (*get_fd)(int *fd);
int (*force_http_10)(void);
int (*get_target_uid)(uid_t *);
int (*get_target_gid)(gid_t *);
unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len);
void (*ini_defaults)(HashTable *configuration_hash);
int phpinfo_as_text;
char *ini_entries;
const zend_function_entry *additional_functions;
unsigned int (*input_filter_init)(void);
};

cli_sapi_module 的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
};