An autoader that use the SPL DirectoryIterator in PHP

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:

  1. http://php.net/manual/en/class.directoryiterator.php
Posted on in PHP