root/trunk/midcom/midcom.core/autoload.php

Revision 14773, 13.9 kB (checked in by rambo, 7 months ago)

scripted whitespace normalization, see r14772

Line 
1 <?php
2 /**
3  * This File is part of the SmartLoader
4  *
5 *
6 * @author Maarten Manders (mandersm@student.ethz.ch)
7 * Adapted to MidCOM by Tarjei Huse
8 * @copyright Copyright 2005, Maarten Manders
9 * @link http://www.maartenmanders.org
10 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
11 * @package midcom
12 */
13
14     /**
15     * PHP Autoload Hook
16     *
17     * Gets called, when an undefined class is being instanciated
18     *
19     * @param string string class name
20     */
21     function __autoload($class_name) {
22         $ldr = SmartLoader::instance();
23         trigger_error("Autoloading");
24         /* initializing loader */
25         if(!$ldr->classes) {
26             $ldr->setCacheFilename($GLOBALS['midcom_config_default']['cache_base_directory'] . "smartloader.cache.php");
27             $ldr->addDir(MIDCOM_ROOT);
28             //$ldr->addDir(MIDCOM_ROOT);
29             $ldr->setClassFileEndings(array('.php'));
30             $ldr->setIgnoreHiddenFiles(true);
31             $ldr->setIgnoreSVN(true);
32         }
33
34         /* load the class or trigger some fatal error on failure */
35         if(!$ldr->loadClass($class_name)) {
36             trigger_error("SmartLoader: Cannot load class '".$class_name."'", E_USER_ERROR);
37         }
38     }
39 if (function_exists('spl_autoload_register'))
40 {
41       ini_set('unserialize_callback_func', 'spl_autoload_call');
42
43       spl_autoload_register('__autoload');
44
45 }
46 else if (!function_exists('__autoload'))
47 {
48       ini_set('unserialize_callback_func', '__autoload');
49 }
50         $ldr = SmartLoader::instance();
51         /* initializing loader */
52         if(!$ldr->classes) {
53             $ldr->setCacheFilename($GLOBALS['midcom_config_default']['cache_base_directory'] . "smartloader.cache.php");
54             $ldr->addDir(MIDCOM_ROOT);
55             //$ldr->addDir(MIDCOM_ROOT);
56             $ldr->setClassFileEndings(array('.php'));
57             $ldr->setIgnoreHiddenFiles(true);
58             $ldr->setIgnoreSVN(true);
59             $ldr->createCache();
60         }
61
62
63     /**
64     * SmartLoader Class
65     *
66     * Singleton. Manages class/interface retrieval, caching and inclusion.
67     *
68     * @package SmartLoader
69     * @author Maarten Manders (mandersm@student.ethz.ch)
70     * @example index.php
71     * @see SmartLoader::instance()
72     * @see SmartLoader::addDir()
73     * @see SmartLoader::loadClass()
74     */
75     class SmartLoader
76     {
77         /**
78         * Class Directories
79         *
80         * Holds the directories SmartLoader scans for class/interface definitions
81         *
82         * @var array
83         * @access private
84         */
85         private $classDirectories = array();
86
87         /**
88         * Cache File Path
89         *
90         * Holds the filename of the generated cache file.
91         *
92         * @var string
93         * @access private
94         */
95         private $cacheFilename = 'smartloader_cache.php';
96
97         /**
98         * Class Index
99         *
100         * Holds an associative array (class name => class file) when scanning.
101         *
102         * @var array
103         * @access private
104         */
105         private $classIndex = array();
106
107         /**
108         * Class File Endings
109         *
110         * Files with these endings will be parsed by the class/interface scanner.
111         *
112         * @var array
113         * @access private
114         */
115         private $classFileEndings = array();
116
117         /**
118         * Follow SymLinks
119         *
120         * Should SmartLoader follow SymLinks when searching class dirs?
121         *
122         * @var boolean
123         * @access private
124         */
125         private $followSymlinks = true;
126
127         /**
128         * Ignore hidden files
129         *
130         * Should SmartLoader ignore hidden files?
131         *
132         * @access private
133         */
134         private $ignoreHiddenFiles = false;
135         /**
136          * If directories starting with .svn should be ignored
137          */
138         private $ignoreSvnDirectories = false;
139         /**
140          * The regular expression to use when parsing for classes
141          */
142         public $classRegularExpression "%(interface|class)\s+(\w+)\s+(extends\s+(\w+)\s+)?(implements\s+\w+\s*(,\s*\w+\s*)*)?{%";
143
144         /**
145          * The static singleton instance
146          */
147         private static $soleInstance = FALSE;
148         /**
149          * The cache of classnames
150          */
151         public $classes = FALSE;
152
153         /**
154         * Constructor
155         *
156         * Initialize SmartLoader
157         *
158         * @access public
159         */
160         private function __construct() {
161             /* do something smart here */
162         }
163         /**
164          * Singleton factory
165          * Remember: Singletons are hidden GLOBALS!
166          * @todo register autoloader instead
167          */
168         public static function instance()
169         {
170             if ( ! self::$soleInstance )
171             {
172                 $class = __CLASS__;
173                 self::$soleInstance = new $class;
174             }
175             return self::$soleInstance;
176         }
177
178
179         /**
180         * Set Cache File Path
181         *
182         * Define a path to store the cache file. Make sure PHP has permission read/write on it.
183         *
184         * @access public
185         * @param string string Cache File Path
186         */
187         public function setCacheFilename($cacheFilename) {
188             $this->cacheFilename = $cacheFilename;
189         }
190
191         /**
192         * Set Class File Endings
193         *
194         * Define which file endings will be considered by the class/interface scanner
195         * An empty array will let the scanner parse any file type.
196         *
197         * @access public
198         * @param array Endings
199         */
200         public function setClassFileEndings($classFileEndings) {
201             $this->classFileEndings = $classFileEndings;
202         }
203
204         /**
205         * Set Follow Symlinks Flag
206         *
207         * Define whether SmartLoader should follow symlinks in when searching the class directory
208         *
209         * @access public
210         * @param boolean follow symlinks
211         */
212         public function setfollowSymlinks($value) {
213             $this->followSymlinks = $value;
214         }
215
216         /**
217         * Set ignore hidden files
218         *
219         * Define whether SmartLoader should ignore hidden files
220         *
221         * @access public
222         * @param boolean value, true to ignore
223         */
224         public function setIgnoreHiddenFiles($value) {
225             $this->ignoreHiddenFiles = $value;
226         }
227         /**
228          * Sets if SVN directories should be ignored
229          * @param boolean true is SVN dirs should be ignored
230          */
231         public function setIgnoreSVN($value) {
232             $this->ignoreSvnDirectories = $value;
233         }
234         /**
235         * Add a directory to retrieve classes/interfaces from
236         *
237         * This function adds a directory to retrieve class/interface definitions from.
238         *
239         * @access public
240         * @param string $directory_path
241         */
242         public function addDir($directory_path) {
243             // add trailing slash
244             if(substr($directory_path, -1) != '/') {
245                 $directory_path .= '/';
246             }
247             if(!in_array($directory_path, $this->classDirectories)) {
248                 $this->classDirectories[] = $directory_path;
249             }
250         }
251
252         /**
253         * Load a Class
254         *
255         * Loads a class by its name
256         * - If the matching class definition file can't be found in the cache,
257         *     it will try once again with $retry = true.
258         * - When retrying, the cached index is invalidated, regenerated and re-included.
259         *
260         * @access public
261         * @param string $class_name
262         * @param boolean $retry used for recursion
263         * @return boolean Success
264         */
265         public function loadClass($class_name, $retry = false) {
266             /* Is the class already defined? (can be omitted in combination with __autoload) */
267             if(class_exists($class_name)) {
268                 return true;
269             }
270
271             /* Is our cache outdated or not available? Recreate it! */
272             if($retry || !is_readable($this->cacheFilename)) {
273                 var_dump($this->cacheFilename);
274                 $this->createCache();
275             }
276
277             /* Include the cache file or raise error if something's wrong with the cache */
278             $this->classes = include($this->cacheFilename);
279             var_dump($this->classes);
280             if(!$this->classes) {
281                 trigger_error("SmartLoader: Cannot include cache file from '".$this->cacheFilename."'", E_USER_ERROR);
282             }
283
284             /* Include requested file. Return on success */
285             if(isset($this->classes[$class_name]) && is_readable($this->classes[$class_name])) {
286                 if(include($this->classes[$class_name])) {
287                     return true;
288                 }
289             }
290
291             /* On failure retry recursively, but only once. */
292             if($retry) {
293                 return false;
294             } else {
295                 return $this->loadClass($class_name, true);
296             }
297         }
298         /**
299          * Checks if a class exists in the class cache
300          */
301         public function classExists($class_name) {
302
303             return isset($this->classes[$class_name]);
304         }
305
306         /**
307         * Create Cache
308         *
309         * - Scans the class dirs for class/interface definitions and
310         *     creates an associative array (class name => class file)
311         * - Generates the array in PHP code and saves it as cache file
312         *
313         * @access private
314         * @param param_type $param_name
315         */
316         public function createCache() {
317             /* Create class list */
318             foreach($this->classDirectories as $dir) {
319                 $this->parseDir($dir);
320             }
321
322             /* Generate php cache file */
323             $cache_content = "<?php\n\t// this is an automatically generated cache file.\n"
324                 ."\t// it serves as 'class name' / 'class file' association index for the SmartLoader\n";
325             foreach($this->classIndex as $class_name => $class_file) {
326                 $cache_content .= "\t\$classes['".$class_name."'] = '".$class_file."';\n";
327             }
328             $cache_content .= " return \$classes; ?>";
329             if($cacheFilename_handle = fopen($this->cacheFilename, "w+")) {
330                 fwrite($cacheFilename_handle, $cache_content);
331                 /* Allow ftp users to access/modify/delete cache file, suppress chmod errors here */
332                 @chmod($this->cacheFilename, 0664);
333             }
334         }
335
336         /**
337         * Parse Directory
338         *
339         * Parses a directory for class/interface definitions. Saves found definitions
340         * in $classIndex. Needless to say: Mind recursion cycles when using symlinks.
341         * TODO: Clean up this method; use SPL, if suitable.
342         *
343         * @access private
344         * @param string $directory_path
345         * @return boolean Success
346         */
347         private function parseDir($directory_path) {
348             if(is_dir($directory_path)) {
349                 if($dh = opendir($directory_path)) {
350                     while(($file = readdir($dh)) !== false) {
351                         $file_path = $directory_path.$file;
352                         if(!$this->ignoreHiddenFiles || $file{0} != '.') {
353                             switch(filetype($file_path))
354                             {
355                                 case 'dir':
356                                     if($file != "." && $file != ".." ) {
357                                         if  ($this->ignoreSvnDirectories && $file == '.svn')
358                                         {
359                                             break;
360                                         }
361                                         /* parse on recursively */
362                                         $this->parseDir($file_path.'/');
363                                     }
364                                     break;
365                                 case 'link':
366                                     if($this->followSymlinks) {
367                                         /* follow link, parse on recursively */
368                                         $this->parseDir($file_path.'/');
369                                     }
370                                     break;
371                                 case 'file':
372                                     /* a non-empty endings array implies an ending check
373                                      * TODO: Write a more sophisticated suffix check. */
374                                     if(!sizeof($this->classFileEndings) || in_array(substr($file, strrpos($file, '.')), $this->classFileEndings)) {
375                                         if($php_file = fopen($file_path, "r")) {
376                                             $size = filesize($file_path);
377                                             if($size > 0 && $buf = fread($php_file, $size)) {
378                                                 $result = array();
379                                                 if(($res = preg_match_all( $this->classRegularExpression, $buf, $result )) != FALSE )
380                                                     {
381                                                     if (!isset ($result[2]) || !is_array($result[2])) {
382                                                         echo $file_path . " didn't contain any classes?!'<br/>";
383                                                         var_dump($res);
384
385                                                         var_dump($result);
386                                                     } else foreach($result[2] as $class_name) {
387                                                         $this->classIndex[$class_name] = $file_path;
388                                                     }
389                                                 }
390                                             }
391                                         }
392                                     }
393                                     break;
394                             }
395                         }
396                     }
397                     return true;
398                 }
399             }
400             return false;
401         }
402     }
403 ?>
Note: See TracBrowser for help on using the browser.