配置文件的加载
通过前几章的学习,我们知道 CLI 是 PHP SAPI 的一种,也会经历 SAPI startup 的阶段,配置文件的解析也是在这个过程中进行,其调用栈如下:
(gdb) bt
#0 php_init_config () at /home/vagrant/php-7.1.4/main/php_ini.c:714
#1 php_module_startup at /home/vagrant/php-7.1.4/main/main.c:2213
#2 php_cli_startup at /home/vagrant/php-7.1.4/sapi/cli/php_cli.c:427
#3 main at /home/vagrant/php-7.1.4/sapi/cli/php_cli.c:1348
在 PHP module 的启动过程中调用 php_init_config 函数来完成配置文件的解析。
/* this will read in php.ini, set up the configuration parameters,
load zend extensions and register php function extensions
to be loaded later */
if (php_init_config() == FAILURE) {
return FAILURE;
}
PHP 配置文件的解析主要分为文件解析和字符串解析,其主要过程都在这个函数中:
-
初始化默认配置,如果当前 SAPI 存在默认配置的初始化函数,则调用该函数来初始化默认配置。例如,CLI 模式的默认配置函数为 sapi_cli_ini_defaults。
-
初始化 extension_lists 来保存配置文件中的扩展。
-
解析主配置文件。
-
解析其他配置文件。
-
解析配置字符串。
PHP 有 3 个命令行参数来控制配置项,分别如下。
|
下面介绍配置文件的加载方式和优先级。
主配置文件
配置解析的第一步是搜索指定路径或者默认路径下的配置文件,配置文件搜索的优先级从高到低如下。
-
使用 -c 指定的配置文件,使用该方式指定后不再搜索后边的目录,配置文件名可以自定义。
-
使用 PHPRC 环境变量指定的配置文件,配置文件名可以自定义,-n 参数下无效。
-
在当前目录下搜索,-n 参数下无效。
-
在 PHP 安装目录 bin 和 etc 下搜索,-n 参数下无效。
-
第 2、3、4 三种方式指定的目录下,如果 php-${sapi}.ini 存在,使用这个配置文件,如 php-cli.ini,否则使用 php.ini。
其他配置文件
如果有很多配置项但是又不想修改默认的配置文件该如何处理呢?PHP 提供了以下两种方式来扩展配置,通过这两种方式指定的目录下的任何以 .ini 为扩展名的文件(包括隐藏文件和链接文件)都会按照文件名称的字母顺序被加载解析。其配置项会覆盖主配置文件(注意:这两种方式互斥,环境变量的方式优先,-n 参数下无效)。
-
在安装 PHP 时由 --with-config-file-scan-dir 参数指定扩展配置文件的目录。
-
如果在安装时没有添加 --with-config-file-scan-dir 参数并且环境变量中存在 PHP_INI_SCAN_DIR,则在该路径下寻找。
配置文件在加载完成后开始解析,解析函数如下:
/* {{{ zend_parse_ini_file()
*/ZEND_API int zend_parse_ini_file(zend_file_handle *fh, zend_bool unbuffered_
errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg){
// code
}
如果同时存在主配置文件和其他配置文件,PHP 会多次调用这个函数来完成配置文件的解析。其解析过程主要是词法和语法的解析,PHP 将解析后的配置以 key-value 的形式保存到名为 configuration_hash 的全局 hashtable 中。值得注意的是,我们在 php.ini 的配置文件中以符合配置文件语法写的任何配置,都会被解析到 configuration_hash。例如,笔者在自己的配置文件中添加了 test = 1 的配置项,通过 gdb 可以看见 configuration_hash 中已经存在这个配置项了:
(gdb) p *configuration_hash.arData[3].key.val@4
$87 = "test"
(gdb) p configuration_hash.arData[3].val.value.str.val
$95 = "1"
非 PHP 的配置项只会保存在 configuration_hash,通过 ini_get 函数无法获取到。不过,PHP 提供了 get_cfg_var 函数来获取 PHP 配置文件中的自定义配置。 |
当配置文件解析完成后,还要进行配置字符串的解析。部分 SAPI 有默认的硬编码配置,例如,在 CLI 模式下有如下默认配置:
const char HARDCODED_INI[] =
"html_errors=0\n"
"register_argc_argv=1\n"
"implicit_flush=1\n"
"output_buffering=0\n"
"max_execution_time=0\n"
"max_input_time=-1\n\0";
除此之外,-d 参数可以不通过配置文件来指定一些独立的配置项,例如:
$ php -d "post_max_size=20M" test.php
这两种方式的配置会在合并后以字符串的方式解析,解析函数如下:
/* {{{ zend_parse_ini_string()
*/
ZEND_API int zend_parse_ini_string(char *str, zend_bool unbuffered_errors, int
scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg)
{
// code
}
在解析配置的过程中,SAPI 硬编码配置优先级最高,会强制覆盖其他配置;其次是 -d 指定的配置;最后是配置文件指定的配置。
完整的解析顺序如图8-1所示。
