A simple class loader for PHP

  1. While playing around with the CodeIgniter library on my LAMP server, I found a need for automatic loading of classes. CodeIgniter is a neat little thing that handles loading of MVC parts, but has no real support for helper or simple data classes. I wanted my models to retrieve data from the database through entity classes by using an ORM library (Doctrine). And like in a typical JPA/Hibernate setup for Java, pass those entity objects to the view.

    The ORM library actually had a class loader with it, but it limited loading within namespaces, and CodeIgniter really doesn't support namespaces. Besides, I think it was very limiting to have to set up different class loaders for every possible namespace in my application.

    I had a hard time finding a class loader to use so I decided to have a look into what this class loading thing was really about, and it became clear it wasn't very hard to do. PHP of version 5.1.2 or later offers a couple of functions; spl_autoload_register and spl_autoload_unregister. They just basically adds or removes a function to a stack that PHP looks through when it stumbles upon a class name which hasn't been defined. That function can then use require to load the class file.

    Below is the class loader I wrote.

    <?php
    
    namespace com\arenybakk;
    
    /**
     * A class loader that loads from a series of locations.
     * 
     * Supports namespaces given that loadable classes are placed in a folder
     * structure matching the namespace path.
     * 
     * Calling the register method enables automatic loading when a class is
     * referenced in code.
     * 
     * @author Are Nybakk <are[at]arenybakk.com>
     * @copyright Copyright 2011, Are Nybakk
     * @license http://www.opensource.org/licenses/mit-license.php MIT license
     */
    class ClassLoader {
    
    
    
      /**
       * @var     Array     Locations for where to look for classes.
       */
      public $locations;
      
      
      
      /**
       * Constructor.
       * 
       * @param   Array     $locations      an optional array of possible class locations.
       */
      public function __construct($locations = Array('classes', 'libraries')) {
      
        $this->locations = $locations;
        
      }
      
      
      
      /**
       * Adds a location where classes may be loaded from.
       * 
       * @param   string    $locations      a location path.
       */
      public function addLocation($location) {
      
        $this->locations[] = $location;
        
      }
      
      
      
      /**
       * Registers the class loader so it may automatically load requested classes.
       */
      public function register() {
      
        spl_autoload_register(Array($this, 'load'));
        
      }
      
      
      
      /**
       * Unregisters the class loader.
       */
      public function unregister() {
      
        spl_autoload_unregister(Array($this, 'load'));
        
      }
      
      
      
      /**
       * Loads a class. If the class loader has been registered, this function is called automatically.
       * 
       * @param   string    $name     a class name. Can contain namespace.
       * @return  bool                true if class exists and was loaded successfully, false otherwise.
       */
      public function load($name) {
      
        return $this->exists($name, true);
        
      }
      
      
      
      /**
       * Check if a class can be loaded.
       * 
       * @param   string    $name     a class name. Can contain namespace.
       * @return  bool                true if class exists, false otherwise.
       */
      public function canLoad($name) {
      
        return $this->exists($name, false);
        
      }
      
      
      
      /**
       * Helper function which looks for a requested file.
       * 
       * @param   string    $name     a class name. Can contain namespace.
       * @param   bool      $load     whether to load class or not.
       * @return  bool                true if class exists (and was loaded successfully), false otherwise.
       */
      private function exists($name, $load) {
      
        //Convert namespace to directory
        $partialPath = str_replace('\\', '/', $name);
        $fullPath = '';
        
        $locations = $this->locations;
        foreach($locations as $location) {
        
          $fullPath = $location . '/' . $partialPath . '.php';
          
          if(file_exists($fullPath)) {
            if($load) {
                require($fullPath);
            }
            return true;
          }
          
        }
        
        return false;
        
      }
      
      
      
    }
    
    ?>

    To use it, simply require the file, create an instance giving the possible locations of your files and register it. The loader handles namespaces as well, if the class files are located in a folder hierarchy reflecting the namespace. Below is an example of how to do it using CodeIgniter. The code goes into a file in the library folder of your application, so that it can be loaded just like any other library for CodeIgniter.

    <?php if (!defined('BASEPATH')) exit('No direct script access allowed'); 
    
    use com\arenybakk\ClassLoader;
    
    /**
     * Classloader CodeIgniter library
     * 
     * @author Are Nybakk <are[at]arenybakk.com>
     * @copyright Copyright 2011, Are Nybakk
     * @license http://www.opensource.org/licenses/mit-license.php MIT license
     */
    class Classloader {
    
    
    
      private $classLoader;
      
      
      
      public function __construct() {
    
        //We need the ClassLoader file
        require_once APPPATH.'libraries/com/arenybakk/ClassLoader.php';
        
        //Enable auto loading from the classes and libraries folders
        $classLoader = new ClassLoader(Array(APPPATH.'classes', APPPATH.'libraries'));
        $classLoader->register();
        $this->classLoader = $classLoader;
        
      }
      
      
      
    }

    I have also been working on a PHP library for modeling, reading and writing classes. I hope to share this with you eventually. Until next time!