深入 Drupal 引导流程 (1)
对于每个请求,Drupal 通过一系列的引导指令阶段来引导它自己。这些阶段在 bootstrap.inc 中定义如下
/**
* First bootstrap phase: initialize configuration.
*/
define('DRUPAL_BOOTSTRAP_CONFIGURATION', 0);
/**
* Second bootstrap phase: try to call a non-database cache
* fetch routine.
*/
define('DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE', 1);
/**
* Third bootstrap phase: initialize database layer.
*/
define('DRUPAL_BOOTSTRAP_DATABASE', 2);
/**
* Fourth bootstrap phase: identify and reject banned hosts.
*/
define('DRUPAL_BOOTSTRAP_ACCESS', 3);
/**
* Fifth bootstrap phase: initialize session handling.
*/
define('DRUPAL_BOOTSTRAP_SESSION', 4);
/**
* Sixth bootstrap phase: load bootstrap.inc and module.inc, start
* the variable system and try to serve a page from the cache.
*/
define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 5);
/**
* Seventh bootstrap phase: find out language of the page.
*/
define('DRUPAL_BOOTSTRAP_LANGUAGE', 6);
/**
* Eighth bootstrap phase: set $_GET['q'] to Drupal path of request.
*/
define('DRUPAL_BOOTSTRAP_PATH', 7);
/**
* Final bootstrap phase: Drupal is fully loaded; validate and fix
* input data.
*/
define('DRUPAL_BOOTSTRAP_FULL', 8);
接下来我将深入每一个引导阶段来逐一分析,以 Drupal 6.11 为版本作源代码。
作为程序入口,我们打开 index.php,就在代码前两行 (line 15, 16)
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
可以看出 Drupal 的引导是通过一个叫 drupal_bootstrap 的函数来完成的,并且传入阶段 DRUPAL_BOOTSTRAP_FULL 为参数。
打开 includes/bootstrap.inc,找到 function drupal_bootstrap (line 977)
function drupal_bootstrap($phase) {
static $phases = array(
DRUPAL_BOOTSTRAP_CONFIGURATION,
DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE,
DRUPAL_BOOTSTRAP_DATABASE,
DRUPAL_BOOTSTRAP_ACCESS,
DRUPAL_BOOTSTRAP_SESSION,
DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE,
DRUPAL_BOOTSTRAP_LANGUAGE,
DRUPAL_BOOTSTRAP_PATH,
DRUPAL_BOOTSTRAP_FULL
), $phase_index = 0;
while ($phase >= $phase_index && isset($phases[$phase_index])) {
$current_phase = $phases[$phase_index];
unset($phases[$phase_index++]);
_drupal_bootstrap($current_phase);
}
}
drupal_bootstrap 是一个循环,并从最低阶段 DRUPAL_BOOTSTRAP_CONFIGURATION 一直往最高阶段 DRUPAL_BOOTSTRAP_FULL 运行,执行方法是调用了 _drupal_bootstrap 函数 (line 987)。函数是一个大的 switch,我们现在将逐一拆开每个阶段 (case) 来分析该函数,
case DRUPAL_BOOTSTRAP_CONFIGURATION:
drupal_unset_globals();
// Start a page timer:
timer_start('page');
// Initialize the configuration
conf_init();
break;
可以看出该阶段执行三个函数,分别是 drupal_unset_globals (line 268), timer_start (line 152), conf_init (line 297),大家可以看看函数的代码,其功能分别为 释放不允许的全局变量;设置计时器,这里创建了一个 $timer['page'] 的计时器;conf_init 的工作比较多,首先判断主机头是否有效,然后调用 conf_path 函数 (line 242) 来获取配置文件的路径,这里需要了解的是 conf_path 的机制,假如现在我们的主机头是 http://www.example.com:8080,那么 Drupal 将会根据以下的顺序来轮询目录,若都找不到目录,才去找 default,
- sites/8080.www.example.com
- sites/www.example.com
- sites/example.com
- sites/com
- sites/default
这里就告诉我们在多域名站的时候,我们如何配置对应的 settings.php 了,读取配置文件后,试着获取 $base_url, $base_path 和 $base_root,若获取不到则根据 URI 来创建这三个全局变量,接着试着获取 $cookie_domain,若获取不到则 $cookie_domain 等于当前域名,最后设置 session_name (cookie 的会话键名字)。