In a previous post I showed a simple example on how to use the SPL Autoloader in PHP. In this example I will show you how to make use of the SPL DirecoryIterator to traverse through the filesystem and look for classes to autoload.
The DirectoryIterator 1 provides a class that makes it easy to view the contents of the file system.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php final class Autoloader { /** * Holds information about all of the class files * @var array */ private static $_cached_classes; /** * Used to Autoload a class * * @param $classname */ public static function load( $classname ) { if( empty( self::$_cached_classes ) ) { self::build_class_cache(); } if( isset( self::$_cached_classes[ $classname ] ) ) { include self::$_cached_classes[ $classname ]; } } /** * Builds a list of all the class files in a directory * * This will go traverse a directory and build a list of all the php files */ private static function build_class_cache() { self::$_cached_classes = array( ); // Specify a list of directories to look in $search_directories = array( __DIR__ . '/classes/' ); foreach( $search_directories as $search_directory ) { //Recursively look in the directory specified $directory_iterator = new RecursiveDirectoryIterator( $search_directory ); $iterator_iterator = new RecursiveIteratorIterator( $directory_iterator, RecursiveIteratorIterator::SELF_FIRST ); foreach( $iterator_iterator as $file ) { //Look for the Class, but filter out some "garbage" if( false === strpos( $file->getFilename(), '~' ) && 0 < strpos( $file->getFilename(), '.php' ) ) { //if a php file is found, add it to the list. self::$_cached_classes[ $file->getBasename( '.php' ) ] = $file->getPathname(); } } } } } spl_autoload_register( array( 'Autoloader', 'load' ) ); |
So now, when I reference a class, the autoloader will check to see if a “cache” of all the filenames is available. If there is nothing available (usually on the first run), then a “cache” will be built.
After that, if a class name exists in the “cache”, we will include the class file.
Update (1/12/2012):
Thanks to Tommy for bringing to my attention that this made it to Reddit. It looks like I have been getting a bit of heat about the file IO. As pointed out in one of my comments, this is a basic implementation.
In my situation, I write the $_cached_classes variable to memcache after the build_class_cache() is run. From then on, every time a page is loaded, I check memcache to repopulate my $_cached_classes variable. Only when needed, will that variable be rebuild with build_class_cache().
I agree that this may not be the best method, especially with namespaces, but I wanted to bring some attention to the SPL.
Notes:
- http://php.net/manual/en/class.directoryiterator.php ↩