class RegistryAutoloadSearcher in Registry Autoload 7
RegistryAutoloadSearcher helper class.
Note: This class is not registered via the registry so it is available while the registry is being rebuild.
Hierarchy
- class \RegistryAutoloadSearcher
Expanded class hierarchy of RegistryAutoloadSearcher
File
- ./
registry_autoload.module, line 138 - Main module for enabling core registry to support namespaced files.
View source
class RegistryAutoloadSearcher {
// @todo Make configurable.
/**
* The namespace $map maps the namespaces provided to subdirectories.
*
* @var array
*/
protected $formatMap = array(
'PSR-0' => 'lib',
'PSR-4' => 'src',
'PHPUnit' => 'tests/src',
'PSR-0/absolute' => '',
'PSR-4/absolute' => '',
'PHPUnit/absolute' => '',
);
/**
* The current content of the {registry_file} table.
*
* @see registry_get_parsed_files()
*
* @var array $parsedFiles
*/
protected $parsedFiles = array();
/**
* Constructs a RegistryAutoloadSearcher object.
*
* @param array $parsed_files
* The current content of the {registry_file} table.
*/
public function __construct(array $parsed_files) {
$this->parsedFiles = $parsed_files;
}
/**
* Finds class files in the given module for the given format.
*
* @param string $path
* The path to search class files in.
* @param string $format
* The format to scan for as specified in the $formatMap.
*
* @return array
* Returns all found php files for the given module and format.
*/
public function findClassFiles($path, $format) {
if (!isset($this->formatMap[$format])) {
return array();
}
$directory = $path;
$subdir = $this->formatMap[$format];
if (!empty($subdir)) {
$directory .= '/' . $subdir;
}
$class_files = file_scan_directory($directory, '/.*.php$/');
return array_keys($class_files);
}
/**
* Processes files containing classes for the given module.
*
* @param array $class_files
* The files to scan for classes.
* @param object $module
* The module object as given to hook_registry_files_alter().
*
* @return array
* An associative array keyed by filename with object values.
* The objects have the following properties:
* - classes: An associative array keyed by namespace+name with properties:
* - type: Type of the class, can be 'interface' or 'class'.
* - name: Name of the class or interface.
* This can be empty if needs_update below is FALSE.
* - filename: The filename of the file.
* - module: The module this file belongs to.
* - weight: The weight of the module this file belongs to.
* - hash: The file_hash() of the filename.
* - needs_update: Whether the registry needs to be updated or not.
*/
public function processFiles(array $class_files, $module) {
$registry = array();
foreach ($class_files as $filename) {
// Check if file exists.
if (!file_exists($filename)) {
continue;
}
$hash = NULL;
$needs_update = $this
->checkFileNeedsUpdate($filename, $hash);
$registry[$filename] = (object) array(
'classes' => array(),
'filename' => $filename,
'module' => $module->name,
'weight' => $module->weight,
// We create a unique structure to populate both registry tables.
'hash' => $hash,
'needs_update' => $needs_update,
);
if ($needs_update) {
$this
->parseFile($registry[$filename], $filename);
}
}
return $registry;
}
/**
* Checks if the is in need of an update.
*
* @param string $filename
* The filename to check against the {registry_file} table.
* @param string $hash
* The hash passed by reference for later usage.
*
* @return bool
* TRUE if the file needs an update, FALSE otherwise.
*/
protected function checkFileNeedsUpdate($filename, &$hash) {
// Check if hash matches still.
$stored_hash = !empty($this->parsedFiles[$filename]['hash']) ? $this->parsedFiles[$filename]['hash'] : NULL;
$hash = hash_file('sha256', $filename);
if (!empty($stored_hash) && $stored_hash == $hash) {
return FALSE;
}
return TRUE;
}
/**
* Parses a file for classes and interfaces, including the namespace.
*
* This lifts the core limitation of not supporting namespaces.
*
* This code is now based on
* \Symfony\Component\ClassLoader\ClassMapGenerator::findClasses()
*
* @param object $entry
* The registry entry as defined in processFiles(). The classes key will be
* updated in the entry if classes can be found.
* @param string $filename
* The filename to parse.
*
* @return bool
* TRUE if classes could be found, FALSE otherwise.
*
* @see _registry_parse_file()
*/
protected function parseFile($entry, $filename) {
$contents = file_get_contents($filename);
$namespace = '';
// Check if this version of PHP supports traits.
$traits = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait';
// Return early if there is no chance of matching anything in this file.
if (!preg_match('{\\b(?:class|interface' . $traits . ')\\s}i', $contents)) {
return array();
}
$tokens = token_get_all($contents);
for ($i = 0, $max = count($tokens); $i < $max; $i++) {
$token = $tokens[$i];
if (is_string($token)) {
continue;
}
$class = '';
$token_name = token_name($token[0]);
switch ($token_name) {
case "T_NAMESPACE":
$namespace = '';
// If there is a namespace, extract it
while (($t = $tokens[++$i]) && is_array($t)) {
if (in_array($t[0], array(
T_STRING,
T_NS_SEPARATOR,
))) {
$namespace .= $t[1];
}
}
$namespace .= '\\';
break;
case "T_CLASS":
case "T_INTERFACE":
case "T_TRAIT":
// Find the classname
while (($t = $tokens[++$i]) && is_array($t)) {
if (T_STRING === $t[0]) {
$class .= $t[1];
}
elseif ($class !== '' && T_WHITESPACE == $t[0]) {
break;
}
}
$class_name = ltrim($namespace . $class, '\\');
$type = 'class';
if ($token[0] == T_INTERFACE) {
$type = 'interface';
}
$entry->classes[$class_name] = array(
'name' => $class_name,
'type' => $type,
);
break;
default:
break;
}
}
return TRUE;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
RegistryAutoloadSearcher:: |
protected | property | The namespace $map maps the namespaces provided to subdirectories. | |
RegistryAutoloadSearcher:: |
protected | property | The current content of the {registry_file} table. | |
RegistryAutoloadSearcher:: |
protected | function | Checks if the is in need of an update. | |
RegistryAutoloadSearcher:: |
public | function | Finds class files in the given module for the given format. | |
RegistryAutoloadSearcher:: |
protected | function | Parses a file for classes and interfaces, including the namespace. | |
RegistryAutoloadSearcher:: |
public | function | Processes files containing classes for the given module. | |
RegistryAutoloadSearcher:: |
public | function | Constructs a RegistryAutoloadSearcher object. |