5 * This file contains the code registry parser engine.
9 * @defgroup registry Code registry
11 * The code registry engine.
13 * Drupal maintains an internal registry of all functions or classes in the
14 * system, allowing it to lazy-load code files as needed (reducing the amount
15 * of code that must be parsed on each request).
19 * Does the work for registry_update().
21 function _registry_update() {
23 // The registry serves as a central autoloader for all classes, including
24 // the database query builders. However, the registry rebuild process
25 // requires write ability to the database, which means having access to the
26 // query builders that require the registry in order to be loaded. That
27 // causes a fatal race condition. Therefore we manually include the
28 // appropriate query builders for the currently active database before the
29 // registry rebuild process runs.
30 $connection_info = Database
::getConnectionInfo();
31 $driver = $connection_info['default']['driver'];
32 require_once DRUPAL_ROOT .
'/includes/database/query.inc';
33 require_once DRUPAL_ROOT .
'/includes/database/select.inc';
34 require_once DRUPAL_ROOT .
'/includes/database/' .
$driver .
'/query.inc';
36 // Get current list of modules and their files.
37 $modules = db_query("SELECT * FROM {system} WHERE type = 'module'")->fetchAll();
38 // Get the list of files we are going to parse.
40 foreach ($modules as
&$module) {
41 $module->info
= unserialize($module->info
);
42 $dir = dirname($module->filename
);
44 // Store the module directory for use in hook_registry_files_alter().
47 if ($module->status
) {
48 // Add files for enabled modules to the registry.
49 foreach ($module->info
['files'] as
$file) {
50 $files["$dir/$file"] = array('module' => $module->name
, 'weight' => $module->weight
);
54 foreach (file_scan_directory('includes', '/\.inc$/') as
$filename => $file) {
55 $files["$filename"] = array('module' => '', 'weight' => 0);
58 $transaction = db_transaction();
60 // Allow modules to manually modify the list of files before the registry
61 // parses them. The $modules array provides the .info file information, which
62 // includes the list of files registered to each module. Any files in the
63 // list can then be added to the list of files that the registry will parse,
64 // or modify attributes of a file.
65 drupal_alter('registry_files', $files, $modules);
66 foreach (registry_get_parsed_files() as
$filename => $file) {
67 // Add the hash for those files we have already parsed.
68 if (isset($files[$filename])) {
69 $files[$filename]['hash'] = $file['hash'];
72 // Flush the registry of resources in files that are no longer on disc
73 // or are in files that no installed modules require to be parsed.
75 ->condition('filename', $filename)
77 db_delete('registry_file')
78 ->condition('filename', $filename)
82 $parsed_files = _registry_parse_files($files);
84 $unchanged_resources = array();
85 $lookup_cache = array();
86 if ($cache = cache_get('lookup_cache', 'cache_bootstrap')) {
87 $lookup_cache = $cache->data
;
89 foreach ($lookup_cache as
$key => $file) {
90 // If the file for this cached resource is carried over unchanged from
91 // the last registry build, then we can safely re-cache it.
92 if ($file && in_array($file, array_keys($files)) && !in_array($file, $parsed_files)) {
93 $unchanged_resources[$key] = $file;
96 module_implements('', FALSE
, TRUE
);
97 _registry_check_code(REGISTRY_RESET_LOOKUP_CACHE
);
99 catch (Exception
$e) {
100 $transaction->rollback();
101 watchdog_exception('registry', $e);
105 // We have some unchanged resources, warm up the cache - no need to pay
106 // for looking them up again.
107 if (count($unchanged_resources) > 0) {
108 cache_set('lookup_cache', $unchanged_resources, 'cache_bootstrap');
113 * Return the list of files in registry_file
115 function registry_get_parsed_files() {
117 // We want the result as a keyed array.
118 $files = db_query("SELECT * FROM {registry_file}")->fetchAllAssoc('filename', PDO
::FETCH_ASSOC
);
123 * Parse all files that have changed since the registry was last built, and save their function and class listings.
126 * The list of files to check and parse.
128 function _registry_parse_files($files) {
129 $parsed_files = array();
130 foreach ($files as
$filename => $file) {
131 if (file_exists($filename)) {
132 $hash = hash_file('sha256', $filename);
133 if (empty($file['hash']) || $file['hash'] != $hash) {
134 // Delete registry entries for this file, so we can insert the new resources.
135 db_delete('registry')
136 ->condition('filename', $filename)
138 $file['hash'] = $hash;
139 $parsed_files[$filename] = $file;
143 foreach ($parsed_files as
$filename => $file) {
144 _registry_parse_file($filename, file_get_contents($filename), $file['module'], $file['weight']);
145 db_merge('registry_file')
146 ->key(array('filename' => $filename))
148 'hash' => $file['hash'],
152 return array_keys($parsed_files);
156 * Parse a file and save its function and class listings.
159 * Name of the file we are going to parse.
161 * Contents of the file we are going to parse as a string.
163 * (optional) Name of the module this file belongs to.
165 * (optional) Weight of the module.
167 function _registry_parse_file($filename, $contents, $module = '', $weight = 0) {
168 if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
169 $query = db_insert('registry')->fields(array('name', 'type', 'filename', 'module', 'weight'));
170 foreach ($matches[2] as
$key => $name) {
171 $query->values(array(
173 'type' => $matches[1][$key],
174 'filename' => $filename,
184 * @} End of "defgroup registry".