Automatically Loading Classes & Modules in PHP

Any serious developer will tell you, __autoload is your friend. It greatly reduces your application’s memory footprint in complex web applications by only loading classes when they’re actually needed, and can take the pain out of adding new features. This is especially useful in MVC framework development.

That said, while working on my own MVC framework (not public, sorry! :( ), I came across the need to keep a structured directory and recursively and selectively load certain file types. While __autoload can be coded to load files recursively as well as from multiple locations (I’ll cover that in a later blog post), there’s serious disadvantages – the biggest one being that your classes cannot raise exceptions, not without implementing an ugly eval() hack.

Instead I wrote a loader which recursively loads files based on an easily maintainable path/filter array (which I place in my MVC’s conf/config.php file):

config.php:

$_inc_paths = array(
         "Libraries" => array(LIB_PATH,"lib_*.php"),
         "Controllers" => array(CTL_PATH, "*_controller.php"),
         "Utilities" => array(ROOT_PATH."/app/utils", "*.php")
);

Next, since this is a MVC framework and everything is being passed through index.php, we define and execute our load routine here:

index.php:

/**
* @desc Dependency loader routine
* @var $path - absolute path to check
* @var $filter - file filter
* @return none
*/

function LoadRecursively($path,$filter) {
    // include any files matching our filters
    $_inc_list=glob("$path/$filter");
    foreach ($_inc_list as $_inc_file) {
        if (substr(basename($_inc_file),0,4)=="lib_") {
                define("api_".basename($_inc_file),TRUE);
        }
        require_once($_inc_file);
    }

    // then scan for any subdirectories
    $_inc_dirlist=glob($path."/*", GLOB_ONLYDIR);
    if (!empty($_inc_dirlist)) {
        // if we find subdirs, do recursion and repeat cycle.
        foreach ($_inc_dirlist as $dir) {
                LoadRecursively($dir,$filter);
        }
    }
}

foreach ($_inc_paths as $name=>$obj) {
    LoadRecursively($obj[0],$obj[1]);    // func(path, filter)
}

The routine isnt really anything original or ingenious. It’s basically the same algorithm you’d use to recursively search for files in most applications. You’ll also probably notice the define() line in my code:

        if (substr(basename($_inc_file),0,4)=="lib_") {
                define("api_".basename($_inc_file),TRUE);
        }

It’s not absolutely necessary, and can be removed. I use it to prevent people from direct-linking to my library files or using them inappropriately. The library files have a line like this at the top of the file, which checks if the api_* is defined and throws an exception if not, preventing the file from being parsed and the class loaded:

defined("api_lib_sanitizer.php") or die("Error: Cannot call lib_sanitize directly!");

Now, some of you purists will probably say, “this is not a good way to do it (loading files recursively), you could wind up using tons of memory! It’s not very scalable!” — well, yes and no. First off, if you have so many files and each one is so large, you’re OBVIOUSLY doing something wrong. Very wrong :) Secondly, hardware is cheap these days. Especially with the emergence of cloud computing. As long as you code efficiently, use proper naming conventions and load based on the appropriate conventions, you should never run into a memory/speed issue.

Case in point: My current MVC framework implements media management (image scaling, video conversion, thumbnail generation), db (including master/slave scaling), various security features including encryption and token generation, captcha, SEO, sanitization, gmaps, error handling, template management, xml handlers and zip handlers, yet uses only 1.5mb total memory footprint (including php and apache process overhead) per connection. Load time is 0.002s on average, on an AMD x2 64 running Ubuntu 9.04, Apache 2.2 and PHP 5.3.

You’re free to use this code under the terms of the GPL v3.

Popularity: 14% [?]

programming - PHP

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

Leave Comment

(required)

(required)