Before:
+function drupal_rebuild_code_registry($check = FALSE) {
+ if ($check) {
+ return $running;
+ }
+ $running = TRUE;
+ // Flush the old registry.
+ // We can't use module_invoke_all here because it depends on the registry
+ // which is currently being rebuilt.
+ foreach ($list as $module) {
+ $function = $module .'_hooks';
+
$result =
(array)$function();
+ foreach ($result as $pattern) {
+ // For example 'form__alter'.
+
$patterns[] =
'/'.
str_replace('__',
'_.*_',
$pattern) .
'/';
+ }
+ }
+ }
+
+ foreach ($list as $module) {
+ _registry_parse_directory
(drupal_get_path('module',
$module),
$patterns);
+ }
+
+ _registry_parse_directory('includes', $patterns);
+ $implementations = _registry_save_resource();
+
cache_set('hooks',
array('patterns' =>
$patterns,
'implementations' =>
$implementations));
+}
+
+/**
+ * Parse all loadable files in a directory and save their function listings.
+ */
+function _registry_parse_directory($path, $patterns) {
+
static $map =
array(T_FUNCTION =>
'function', T_CLASS =>
'class', T_INTERFACE =>
'interface');
+ foreach ($files as $filename => $file) {
+
while ($token =
next($tokens)) {
+ $result = _registry_save_resource($token, $tokens, $map[$token[0]], $filename, $patterns);
+ // If this is a disabled module then we skip the whole file.
+ if ($result == -1) {
+ continue 2;
+ }
+ // We skip the body because classes might contain functions.
+ _registry_skip_body($tokens);
+ }
+ }
+ }
+}
+
+/**
+ * Save a resource into the database.
+ *
+ * @param mixed $token
+ * @param array $tokens
+ * @param string $type
+ * @param string $module_path
+ * @param string $filename
+ */
+function _registry_save_resource($token = NULL, &$tokens = NULL, $type = NULL, $filename = NULL, $patterns = NULL) {
+
static $implementations,
$resources,
$dirs,
$node_functions;
+ return $implementations;
+ }
+
if (empty($node_functions)) {
+ foreach ($types as $node_type) {
+ $module = $node_type->module == 'node' ? 'node_content' : $node_type->module;
+
foreach (array('load',
'validate',
'insert',
'update',
'delete',
'view',
'prepare',
'form') as $hook) {
+ $node_functions[$module .'_'. $hook] = $module;
+ }
+ }
+ }
+
next($tokens);
// Eat a space.
+
$token =
next($tokens);
+ if ($token == '&') {
+
$token =
next($tokens);
+ }
+ $resource_name = $token[1];
+
if (isset($resources[$type][$resource_name])) {
+ return;
+ }
+ $resources[$type][$resource_name] = TRUE;
+
$file_parts =
explode('.',
$filename);
+ $module = '';
+ $hook = '';
+
$count =
count($file_parts);
+
if (isset($node_functions[$resource_name]) &&
$type ==
'function') {
+ $module = $node_functions[$resource_name];
+ }
+ else {
+ if ($count == 2 && $file_parts[1] == 'inc') {
+
if (!
isset($dirs[$filename])) {
+
$dir_parts =
explode('/',
$file_parts[0]);
+ }
+ $module = $dirs[$filename];
+ }
+ if (($count == 2 && ($file_parts[1] == 'module' || $file_parts[1] == 'install')) || ($count == 3 && $file_parts[2] == 'inc')) {
+ // We indicate that this file needs to be skipped.
+ return -1;
+ }
+ }
+ }
+
if ($module &&
strpos($resource_name,
$module) ===
0) {
+ foreach ($patterns as $pattern) {
+ $implementations[$hook][] = $module;
+ }
+ }
+ }
+
db_query("INSERT INTO {registry} (name, type, module, hook, file) VALUES ('%s', '%s', '%s', '%s', '%s')",
array($resource_name,
$type,
$module,
$hook,
"./$filename"));
+}
+
+/**
+ * Skip the body of a code block, as defined by { and }.
+ *
+ * This function assumes that the body starts at the next instance
+ * of { from the current position.
+ *
+ * @param array $tokens
+ */
+function _registry_skip_body(&$tokens) {
+ $num_braces = 1;
+
+ $token = '';
+ // Get to the first open brace.
+
while ($token !=
'{' &&
($token =
next($tokens)));
+
+ // Scan through the rest of the tokens until we reach the matching
+ // end brace.
+
while ($num_braces &&
($token =
next($tokens))) {
+ if ($token == '{') {
+ ++$num_braces;
+ }
+ elseif ($token == '}') {
+ --$num_braces;
+ }
+ }
+}
After:
+/**
+ * @defgroup registry Code registry
+ * @{
+ * The code registry engine.
+ *
+ * Drupal maintains an internal registry of all functions or classes in the
+ * system. That in turn allows Drupal to lazy-load code files selectively
+ * as needed, reducing the amount of code that needs to be parsed on each
+ * request. The list of files included is then cached per menu callback
+ * so that they can be loaded by the menu router. That way, a given page
+ * request will have all the code it needs and little else, minimizing the
+ * time wasted parsing unneeded code.
+ */
+
+/**
+ * Rescan all enabled modules and rebuild the registry.
+ *
+ * This function rescans all code in modules or the includes directory and
+ * stores a mapping of function, file, and hook implementation to the database.
+ *
+ * @param $check
+ * If TRUE, return whether or not a rebuild is currently in progress. That is
+ * needed so that this process can call module_implements(), which in turn
+ * needs to bypass the registry if the registry is still in the process of
+ * being rebuilt.
+ * @return
+ * If $checked is TRUE, returns TRUE if the registry is in the process of
+ * being rebuilt and FALSE otherwise. If $checked is FALSE, this function
+ * returns nothing.
+ */
+function drupal_rebuild_code_registry($check = FALSE) {
+
+ // Simple recursion blocking. See DocBlock above.
+ if ($check) {
+ return $running;
+ }
+ $running = TRUE;
+ // Flush the old registry.
+ // We can't use module_invoke_all here because it depends on the registry
+ // which is currently being rebuilt.
+ foreach ($list as $module) {
+ $function = $module .'_hooks';
+
$result =
(array)$function();
+ foreach ($result as $pattern) {
+ // For example 'form__alter'.
+
$patterns[] =
'/'.
str_replace('__',
'_.*_',
$pattern) .
'/';
+ }
+ }
+ }
+
+ foreach ($list as $module) {
+ _registry_parse_directory
(drupal_get_path('module',
$module),
$patterns);
+ }
+
+ _registry_parse_directory('includes', $patterns);
+ $implementations = _registry_hook_implementations();
+
cache_set('hooks',
array('patterns' =>
$patterns,
'implementations' =>
$implementations));
+
+ // Reset our recursion blocker.
+ $running = FALSE;
+}
+
+/**
+ * Parse all loadable files in a directory and save their function and class listings.
+ *
+ * @param $path
+ * The path relative to Drupal root to scan.
+ * @param $patterns
+ * The function pattern to identify as a hook. That allows us to record
+ * what hook implementations exist and in what module/file.
+ */
+function _registry_parse_directory($path, $patterns) {
+
static $map =
array(T_FUNCTION =>
'function', T_CLASS =>
'class', T_INTERFACE =>
'interface');
+
+
+ foreach ($files as $filename => $file) {
+
while ($token =
next($tokens)) {
+ // Ignore all tokens except for those we are specifically saving.
+ if ($resource_name = _registry_get_resource_name($tokens, $map[$token[0]]) ) {
+ $module = _registry_get_resource_module($resource_name, $filename);
+
if ($module !=
'includes' && !
in_array($module,
$active_modules)) {
+ // If this is a disabled module then we skip the whole file.
+ continue 2;
+ }
+
+ // Now save the resource record to the database.
+ $result = _registry_save_resource($resource_name, $map[$token[0]], $module, $hook, $filename);
+ // We skip the body because classes might contain functions.
+ _registry_skip_body($tokens);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Derive the name of the next resource in the token stream.
+ *
+ * @param array $tokens
+ * The collection of tokens for the current file being parsed.
+ * @param string $type
+ * The human-readable token name: One of "function", "class", or "interface".
+ * @return
+ * The name of the resource, or FALSE if the resource has already been processed.
+ */
+function _registry_get_resource_name(&$tokens, $type) {
+ // Keep a running list of all resources we've saved so far, so that we never
+ // save one more than once.
+
+ // Determine the name of the resource.
+
next($tokens);
// Eat a space.
+
$token =
next($tokens);
+ if ($token == '&') {
+
$token =
next($tokens);
+ }
+ $resource_name = $token[1];
+
+ // Ensure that we never save it more than once.
+
if (isset($resources[$type][$resource_name])) {
+ return FALSE;
+ }
+ $resources[$type][$resource_name] = TRUE;
+
+ return $resource_name;
+}
+
+/**
+ * Determine the module that the given resource beongs to.
+ *
+ * In the case of node "hooks", the module is determined by calculating all
+ * possible node hooks and the module they correspond to. Otherwise, the module
+ * is derived from the file name or directory name of the file.
+ *
+ * Detectable files follow one of the following patterns:
+ * - <module>.module
+ * - <module>.install
+ * - <module>.<some-arbitrary-string>.inc
+ * - <module>/<some-arbitrary-string>.inc
+ *
+ * Note that the last option will treat any code in Drupal's core "includes"
+ * directory as belonging to the module "includes". That is by design.
+ *
+ * In order for a module to provide a hook on behalf of another module, the
+ * name of the file the implementation exists in must match the module the hook
+ * applies to, not the providing module. That is, if module foo is providing
+ * the implementation of hook_example() on behalf of module bar, then the function
+ * must reside in foo/bar.something.inc for it to associate with module bar
+ * correctly.
+ *
+ * @param string $resource_name
+ * The name of the resource; the function or class name.
+ * @param string $filename
+ * The name of the file in which the resource resides, relative to Drupal root.
+ * @return
+ * The name of the module that "owns" the resource.
+ */
+function _registry_get_resource_module($resource_name, $filename) {
+
static $dirs,
$node_functions;
+
+ // Node "hooks" aren't "real hooks", but still get called indirectly. Therefore,
+ // we build up a list of all possible node hooks for the current node types
+ // that we can match against later.
+
if (empty($node_functions)) {
+ foreach ($types as $node_type) {
+ $module = $node_type->module == 'node' ? 'node_content' : $node_type->module;
+
foreach (array('load',
'validate',
'insert',
'update',
'delete',
'view',
'prepare',
'form') as $hook) {
+ $node_functions[$module .'_'. $hook] = $module;
+ }
+ }
+ }
+
+ // Extract the module from the file name or directory name.
+
$file_parts =
explode('.',
$filename);
+ $module = '';
+ $hook = '';
+
$count =
count($file_parts);
+
if (isset($node_functions[$resource_name]) &&
$type ==
'function') {
+ $module = $node_functions[$resource_name];
+ }
+ else {
+ if ($count == 2 && $file_parts[1] == 'inc') {
+
if (!
isset($dirs[$filename])) {
+
$dir_parts =
explode('/',
$file_parts[0]);
+ }
+ $module = $dirs[$filename];
+ }
+ if (($count == 2 && ($file_parts[1] == 'module' || $file_parts[1] == 'install')) || ($count == 3 && $file_parts[2] == 'inc')) {
+ }
+ }
+
+ return $module;
+}
+