Dynamic Lazy Loading

While reading a blog post the other day about the benefits of lazy loading, I took a look at one of my own code bases and thought about how it could benefit from lazy loading. A majority of tables in the database where had their own specific class file, some classes were group in the same file. Other classes were grouped in subfolders. All of these separate files were in one directory models, which was included on every page load. This ended up being some 150 different files and 10 megabytes of parsed code. This definitely seemed like an area for improvement.
Given the mangled naming structure using a naming schema was immediately ruled out of consideration. I next thought about creating a map, the downside to this was map maintenance. I hate having to do stuff in 3 places, add the table to the database, create the php file, and then add it to the map. I thought there must be an easier way to do this, and there was scripted model map generation.
Since my code base could was already completely able to load every model with out a problem there were three things left to do.

  1. Load the code base and figure out which classes were default to php and which were my own.
  2. Figure out what file each class was declared in
  3. Store the data to a flat file for later reading.

1. Figuring Out Whose Class It Is:

To figure out which classes were mind and which were natively part of php is a rather simple task using the get_declared_classes() function I was able to determine which classes were native to php. After completely loading the code base, I ran the function again. The difference of the initial run and the second run is my defined classes.

2. Where Was It Declared:

To figure out where each class is declared you use PHP reflection.

<?php

foreach($class_list as $classname) {
    $reflector = new ReflectionClass($classname);
    $ini_config_data[strtolower($classname)] = $reflector->getFileName();
}

?>
view raw gistfile1.php This Gist brought to you by GitHub.

Now ini_cofig_data is a hash of classname => absolute/path/to/class.php

3. How To Store It:

Incase you couldn’t guess I used an ini file. PHP has native ini parsing to array (parse_ini_file) so the read is extremely simple. The write ends up being rather simple as well.

<?php
$fp = fopen('object_map.ini', 'w');

foreach($ini_config_data as $class => $filename) {
    $write = $class . ' = ' . $filename . PHP_EOL;
    fwrite($fp, $write, strlen($write));
}

fclose($fp);
?>
view raw gistfile1.php This Gist brought to you by GitHub.

Writing __autoload:

The autoload function is very straight forward, it takes 1 parameter the name of the class to load. We must look this up from are ini array and load it. The code could look like this:

<?php
$model_object = parse_ini_file('object_map.ini');
function __autoload($class_name) {
    global $model_object;
    $class_name = strtolower($class_name);
    if (!isset($model_object[$class_name])) {
        exit('invalid class name');
    }
    
    require_once($model_object[$class_name]);
}
?>
view raw gistfile1.php This Gist brought to you by GitHub.

There is a bit of hack to get model_object global, but you can add it as an attribute to your framework that is returned via a static call? Just don’t read the file every time

Now after I create a new model, I simply rerun the script and I’m good to go.