Drupal通过spl_autoload_register()注册类加载器实现自动加载:
function _drupal_bootstrap_database() { // ... .... spl_autoload_register('drupal_autoload_class'); spl_autoload_register('drupal_autoload_interface'); }
再来看看类加载器是如何实现的?
function drupal_autoload_interface($interface) { return _registry_check_code('interface', $interface); } function drupal_autoload_class($class) { return _registry_check_code('class', $class); } function _registry_check_code($type, $name = NULL) { static $lookup_cache, $cache_update_needed; if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name)) { return TRUE; } if (!isset($lookup_cache)) { $lookup_cache = array(); if ($cache = cache_get('lookup_cache', 'cache_bootstrap')) { $lookup_cache = $cache->data; } } // When we rebuild the registry, we need to reset this cache so // we don't keep lookups for resources that changed during the rebuild. if ($type == REGISTRY_RESET_LOOKUP_CACHE) { $cache_update_needed = TRUE; $lookup_cache = NULL; return; } // Called from drupal_page_footer, we write to permanent storage if there // changes to the lookup cache for this request. if ($type == REGISTRY_WRITE_LOOKUP_CACHE) { if ($cache_update_needed) { cache_set('lookup_cache', $lookup_cache, 'cache_bootstrap'); } return; } // $type is either 'interface' or 'class', so we only need the first letter to // keep the cache key unique. $cache_key = $type[0] . $name; if (isset($lookup_cache[$cache_key])) { if ($lookup_cache[$cache_key]) { require_once DRUPAL_ROOT . '/' . $lookup_cache[$cache_key]; } return (bool) $lookup_cache[$cache_key]; } // This function may get called when the default database is not active, but // there is no reason we'd ever want to not use the default database for // this query. $file = Database::getConnection('default', 'default')->query("SELECT filename FROM {registry} WHERE name = :name AND type = :type", array( ':name' => $name, ':type' => $type, )) ->fetchField(); // Flag that we've run a lookup query and need to update the cache. $cache_update_needed = TRUE; // Misses are valuable information worth caching, so cache even if // $file is FALSE. $lookup_cache[$cache_key] = $file; if ($file) { require_once DRUPAL_ROOT . '/' . $file; return TRUE; } else { return FALSE; } }
留意下面这段代码:
$file= Database::getConnection('default','default')->query("SELECT filename FROM {registry} WHERE name = :name AND type = :type",array( ':name' => $name, ':type' => $type, ))->fetchField();
类加载器要自动加载DatabaseLog这个类,需要去哪里找对应的文件?
Drupal采用了注册表的方式解决这个问题,它将所有可用的类和接口以及它们对应的文件保存一个名为registry的数据表中。类加载器依据类名就可以简单地找到对应的文件。