/environment/classes/AutoLoader.class.php
https://github.com/cj/Project-Pier · PHP · 300 lines · 123 code · 32 blank · 145 comment · 28 complexity · 0eafc30e203609e92551355f6690315a MD5 · raw file
- <?php
-
- /**
- * Fancy class loader which uses an index
- *
- * This class is based on SmartLoader
- *
- * @package Environment
- */
- class AutoLoader {
-
- /**
- * mod settings for the index file
- */
- const INDEX_FILE_MOD = 0775;
-
- /**
- * Name of the $GLOBALS var where we'll store class names
- *
- * @var string
- */
- const GLOBAL_VAR = 'autoloader_classes';
-
- /**
- * Filename of index file
- *
- * @var string
- */
- private $index_filename = 'autoloader_index.php';
-
- /**
- * Array of directory paths that need to be parsed
- *
- * @var array
- */
- private $parse_directories = array();
-
- /**
- * Extension of files that need to be scaned
- *
- * @var string
- */
- private $scan_file_extension = 'class.php';
-
- /**
- * Ignore hidden and system files
- *
- * @var boolean
- */
- private $ignore_hidden_files = true;
-
- /**
- * Cached array of parsed directories, keep it from endless loop
- *
- * @var array
- */
- private $parsed_directories = array();
-
- /**
- * Class index
- *
- * @var array
- */
- private $class_index = array();
-
- // ---------------------------------------------------
- // Doers
- // ---------------------------------------------------
-
- /**
- * Loads a class by its name
- *
- * @access public
- * @param string $class_name
- * @throws Exception
- * @return boolean Success
- */
- public function loadClass($load_class_name) {
- static $retrying = false; // is this our second loading attempt?
-
- $class_name = strtoupper($load_class_name);
-
- /* Recreate the index file, if outdated */
- if (!isset($GLOBALS[self::GLOBAL_VAR])) {
- if ($retrying || !is_readable($this->getIndexFilename())) {
- $this->createCache();
- if (!is_readable($this->getIndexFilename())) {
- throw new Exception('SmartLoader index file "'.$this->indexFilename.'" is not readable!');
- } // if
- } // if
- include $this->getIndexFilename();
- } // if
-
- /* include the needed file or retry on failure */
- if (isset($GLOBALS[self::GLOBAL_VAR][$class_name])) {
- if (@include($GLOBALS[self::GLOBAL_VAR][$class_name])) {
- return true;
- } else {
- if ($retrying) {
- throw new Exception('Class file "' . $GLOBALS[self::GLOBAL_VAR][$class_name] . '" for class "'.$class_name.'" cannot be included!');
- } // if
- } // if
- } elseif ($retrying) {
- /* we failed while retrying. this is bad. */
- throw new Exception('Could not find class file for "'.$class_name.'"');
- } // if
-
- /* including failed. try again. */
- unset($GLOBALS[self::GLOBAL_VAR]);
- $retrying = true;
- return $this->loadClass($class_name);
- } // loadClass
-
- /**
- * - Scans the class dirs for class/interface definitions and
- * creates an associative array (class name => class file)
- * - Generates the array in PHP code and saves it as index file
- *
- * @access private
- * @param param_type $param_name
- * @throws Exception
- */
- private function createCache() {
- if (is_array($this->parse_directories) && count($this->parse_directories)) {
- foreach ($this->parse_directories as $dir) {
- $this->parseDir($dir);
- }
- } // if
- $this->createIndexFile();
- } // createCache
-
- /**
- * Write out to the index file
- *
- * @access private
- * @throws Exception
- */
- private function createIndexFile() {
- /* generate php index file */
- $index_content = "<?php\n";
- foreach ($this->class_index as $class_name => $class_file) {
- $index_content .= "\t\$GLOBALS['autoloader_classes'][". var_export(strtoupper($class_name), true) . "] = " . var_export($class_file, true) . ";\n";
- } // foreach
- $index_content .= "?>";
- if (!@file_put_contents($this->getIndexFilename(), $index_content)) {
- throw new Exception('Could not write to "'.$this->getIndexFilename().'". Make sure, that your webserver has write access to it.');
- } // if
-
- /* Apply mod rights */
- @chmod($this->getIndexFilename(), self::INDEX_FILE_MOD );
- } // createIndexFile
-
- /**
- * Parses a directory for class/interface definitions. Saves found definitions
- * in $classIndex
- *
- * @access private
- * @param string $directory_path
- * @throws Exception
- * @return boolean Success
- */
- private function parseDir($directory_path) {
- $directory_path = with_slash($directory_path);
- if (in_array($directory_path, $this->parsed_directories)) {
- return;
- } else {
- $this->parsed_directories[] = $directory_path;
- } // if
-
- $dir = dir($directory_path);
- while (false !== ($entry = $dir->read())) {
- if ($entry == '.' || $entry == '..') {
- continue;
- } // if
- $path = $directory_path . $entry;
- if (is_dir($path)) {
- if ($this->getIgnoreHiddenFiles() && ($entry[0] == '.')) {
- continue;
- } // if
- if (!is_readable($path)) {
- continue;
- } // if
- $this->parseDir($path);
- } elseif (is_file($path)) {
- if (!is_readable($path)) {
- continue;
- } // if
- if (str_ends_with($path, $this->getScanFileExtension())) {
- $this->parseFile($path);
- } // if
- } // if
- } // if
- $dir->close();
- } // parseDir
-
- /**
- * Parse a file for PHP classes and add them to our classIndex
- *
- * @access private
- * @param string path to file
- * @throws Exception
- */
- private function parseFile($path) {
- if (!$buf = @file_get_contents($path)) {
- throw new Exception('Couldn\'t read file contents from "'.$path.'".');
- } // if
-
- /* searching for classes */
- if (preg_match_all("%(interface|class)\s+(\w+)\s+(extends\s+(\w+)\s+)?(implements\s+\w+\s*(,\s*\w+\s*)*)?{%im", $buf, $result)) {
- foreach ($result[2] as $class_name) {
- $this->class_index[$class_name] = str_replace('\\', '/', $path);
- } // if
- } // if
- } // parseFile
-
- // ---------------------------------------------------
- // Getters and setters
- // ---------------------------------------------------
-
- /**
- * Add directory that need to be scaned
- *
- * @param stirng $path Direcotry path
- * @return null
- */
- function addDir($path) {
- if (is_dir($path)) {
- $this->parse_directories[] = $path;
- } // if
- } // addDir
-
- /**
- * Get index_filename
- *
- * @access public
- * @param null
- * @return string
- */
- function getIndexFilename() {
- return $this->index_filename;
- } // getIndexFilename
-
- /**
- * Set index_filename value
- *
- * @access public
- * @param string $value
- * @return null
- */
- function setIndexFilename($value) {
- $this->index_filename = $value;
- } // setIndexFilename
-
- /**
- * Get scan_file_extension
- *
- * @access public
- * @param null
- * @return string
- */
- function getScanFileExtension() {
- return $this->scan_file_extension;
- } // getScanFileExtension
-
- /**
- * Set scan_file_extension value
- *
- * @access public
- * @param string $value
- * @return null
- */
- function setScanFileExtension($value) {
- $this->scan_file_extension = $value;
- } // setScanFileExtension
-
- /**
- * Get ignore_hidden_files
- *
- * @access public
- * @param null
- * @return boolean
- */
- function getIgnoreHiddenFiles() {
- return $this->ignore_hidden_files;
- } // getIgnoreHiddenFiles
-
- /**
- * Set ignore_hidden_files value
- *
- * @access public
- * @param boolean $value
- * @return null
- */
- function setIgnoreHiddenFiles($value) {
- $this->ignore_hidden_files = $value;
- } // setIgnoreHiddenFiles
-
- } // AutoLoader
-
- ?>