PHP内核源码阅读过程(一)

最近在阅读PHP的内核,所以把过程记下来。

本人使用cli方式启动php,版本是7.3.3, 调试平台是centos6.5。

cli方式启动的入口位于 sapi/cli/php_cli.c main 

1. 函数save_ps_args

这个函数是进来后调用的第一个函数,原型:char** save_ps_args(int argc, char** argv) 

其功能是保存命令行参数,检查命令行参数和环境变量。

保存命令行参数:

save_argc = argc;
save_argv = argv;

检查命令行参数:

for (i = 0; (non_contiguous_area == 0) && (i < argc); i++)
{
    if (i != 0 && end_of_area + 1 != argv[i])
        non_contiguous_area = 1;
    end_of_area = argv[i] + strlen(argv[i]);
}

检查环境变量:

for (i = 0; (non_contiguous_area == 0) && (environ[i] != NULL); i++)
{
    if (end_of_area + 1 != environ[i])
        non_contiguous_area = 1;
    end_of_area = environ[i] + strlen(environ[i]);
}

将环境变量保存到新地址,同时备份一个原始内容:

new_environ = (char **) malloc((i + 1) * sizeof(char *));
frozen_environ = (char **) malloc((i + 1) * sizeof(char *));
if (!new_environ || !frozen_environ)
    goto clobber_error;
for (i = 0; environ[i] != NULL; i++)
{
    new_environ[i] = strdup(environ[i]);
    if (!new_environ[i])
        goto clobber_error;
}
new_environ[i] = NULL;
environ = new_environ;
memcpy((char *)frozen_environ, (char *)new_environ, sizeof(char *) * (i + 1));

将命令行参数保存到新地址:

char** new_argv;
int i;

new_argv = (char **) malloc((argc + 1) * sizeof(char *));
if (!new_argv)
    goto clobber_error;
for (i = 0; i < argc; i++)
{
    new_argv[i] = strdup(argv[i]);
    if (!new_argv[i]) {
        free(new_argv);
        goto clobber_error;
    }
}
new_argv[argc] = NULL;

argv = new_argv;

2. 设置额外的函数 

cli_sapi_module.additional_functions = additional_functions;

有三个函数,其定义如下:

static const zend_function_entry additional_functions[] = {
	ZEND_FE(dl, arginfo_dl)
	PHP_FE(cli_set_process_title,        arginfo_cli_set_process_title)
	PHP_FE(cli_get_process_title,        arginfo_cli_get_process_title)
	PHP_FE_END
};

3. signal(SIGPIPE, SIG_IGN), 忽略SIGPIPE信号。如果对端的socket关闭,会触发SIGPIPE信号,系统默认的处理方式是杀掉这个进程。这里不能被杀掉。

zend_signal_startup初始化信号。

4. 解析命令

        while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2))!=-1) {
		switch (c) {
			case 'c':
				if (ini_path_override) {
					free(ini_path_override);
				}
 				ini_path_override = strdup(php_optarg);
				break;
			case 'n':
				ini_ignore = 1;
				break;
			case 'd': {
				/* define ini entries on command line */
				size_t len = strlen(php_optarg);
				char *val;

				if ((val = strchr(php_optarg, '='))) {
					val++;
					if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
						ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
						memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
						ini_entries_len += (val - php_optarg);
						memcpy(ini_entries + ini_entries_len, "\"", 1);
						ini_entries_len++;
						memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
						ini_entries_len += len - (val - php_optarg);
						memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
						ini_entries_len += sizeof("\n\0\"") - 2;
					} else {
						ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
						memcpy(ini_entries + ini_entries_len, php_optarg, len);
						memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
						ini_entries_len += len + sizeof("\n\0") - 2;
					}
				} else {
					ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
					memcpy(ini_entries + ini_entries_len, php_optarg, len);
					memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
					ini_entries_len += len + sizeof("=1\n\0") - 2;
				}
				break;
			}
#ifndef PHP_CLI_WIN32_NO_CONSOLE
			case 'S':
				sapi_module = &cli_server_sapi_module;
				cli_server_sapi_module.additional_functions = server_additional_functions;
				break;
#endif
			case 'h': /* help & quit */
			case '?':
				php_cli_usage(argv[0]);
				goto out;
			case 'i': case 'v': case 'm':
				sapi_module = &cli_sapi_module;
				goto exit_loop;
			case 'e': /* enable extended info output */
				use_extended_info = 1;
				break;
		}
	}

这里只讲一下 'S' 参数,这个是启动内置的web服务器,所以会载入web服务器有关的一些函数,其 server_additional_functions定义如下:

const zend_function_entry server_additional_functions[] = {
	PHP_FE(cli_set_process_title,        arginfo_cli_set_process_title)
	PHP_FE(cli_get_process_title,        arginfo_cli_get_process_title)
	PHP_FE(apache_request_headers, arginfo_no_args)
	PHP_FE(apache_response_headers, arginfo_no_args)
	PHP_FALIAS(getallheaders, apache_request_headers, arginfo_no_args)
	PHP_FE_END
};

5. 初始化模块参数

	sapi_module->ini_defaults = sapi_cli_ini_defaults;
	sapi_module->php_ini_path_override = ini_path_override;
	sapi_module->phpinfo_as_text = 1;
	sapi_module->php_ini_ignore_cwd = 1;

sapi_cli_ini_defaults是默认ini配置的读取函数,定义如下:

#define INI_DEFAULT(name,value)\
	ZVAL_NEW_STR(&tmp, zend_string_init(value, sizeof(value)-1, 1));\
	zend_hash_str_update(configuration_hash, name, sizeof(name)-1, &tmp);\

static void sapi_cli_ini_defaults(HashTable *configuration_hash)
{
	zval tmp;
	INI_DEFAULT("report_zend_debug", "0");
	INI_DEFAULT("display_errors", "1");
}

ini_path_override是从参数'c'传入的ini文件路径或目录。

 

接下来看看sapi的启动。

你可能感兴趣的:(PHP内核)