Optimizing code with __autoload()
- Development, PHP
- March 13, 2007
With the advent of PHP5 a new tool was available to all who wished to optimize their code, its called __autoload. This function can reduce the time lost by having to include object and class files in your code. But how do you proceed in creating an __autoload function to optimize code?
Autoload is responsible for a simple task: when PHP identifies a new class call (like new ObjectX) it looks for this class’s declaration, however, if it doesn’t find that declaration it summons the autooad method, which should include the proper file o PHP can instantiate that class.
What are the “pros”?
In large site or systems, if the developer is the least organized, classes and objects are declared in external files, maybe summing up large numbers of external files, even more if working in an OO methodology. When this happens usually a central file in the system is responsible for including all these external files, regardless of their need in the script that’s being executed. This can cause an overhead, loading useless files, and increasing the time needed to process each action.
Using autoload makes it possible to load external files, only in cases where it’s actually needed and called for, thus avoiding the overhead and saving file access and processing times.
What are de “cons”?
The old wise man already said every coin has two sides. Even while saving time not load unneeded files, it is possible to cause a delay at the moment of instantiating new class. This delay can be considered too small if compared to the time gained, but hey, I had to cite at least on “con”!
How do I implement an __autoload() on my site?
The first step is to analyze your sites file structure, and design an autoload function according to that structure, setting a pattern for naming files and object, thus avoiding problems.
In this example we have three possible cases:
- Classes of the ezComponents library: located in PHP’s include_path
- General classes: located in the /lib folder
- Business logic classes: Located in the /lib/gcc/system folder (where system represents the sub-system, in this case, inet, ind and comm)
The autoload function should know in which of the preceding folders to look for the specific class its searching for. But the function receives only one argument, the name of the class.
Thus, the magic trick is actually in creating patters for class names. In our case three patterns were created:
- ezComponents classes always begin with “ezc”
- Business logic classes are named like: gcc{cod_system}{Object}, for instance: gccInetClient
- Other classes have no naming restraint, other than not following the rules above
Now PHP can figure out where the file is located, but what’s the file’s actual name? Here we need to set another pattern; the filename must be according to the class name, something like {class_name}.class.php, respecting case (upper and lower)
Engraving these patterns in stone we can now continue our mission in a very simple manner. Our function must identify which type of class it’s manipulating, and execute the associated algorithm to get the correct file. Only in the case of business logic classes I decided to create sub-folders according to sub-system, but that is solved with a simple regular expression.
function \_\_autoload( $className ) { if (strpos($className,'ezc') !== false){ //ezComponents class ezcBase::autoload( $className ); }elseif (strpos($className,'gcc') !== false){ //business logic class //Separate fomr the name, classname, folder and sub-system ereg("(gcc)(\[A-Z\]{1}\[^A-Z\]\*)(.\*)$",$className,$bits); //Includefile by combining the data found include\_once("lib/".$bits\[1\]."/".strtolower($bits\[2\])."/".$className.".class.php"); }else{ //common class include\_once("lib/".$className.".class.php"); } }
On a short note, autoload is a global function, i.e. cannot be declared twice. So it best to declare this function in a central file of the system, but in a well structured system this should not be a problem.
What’s the final impact on my code?
If we compare the results in a single file, by loading time, we may not be too impressed wth the outcome, but take into consideration multiple concurrent connection and thousands of loadings each day, well, do the math.
For argument’s sake I created for this example two parallel structures where classes were included and instantiated. In one example I used autoload, in the other I just loaded all the class files.
I total, 8 classes were included from external files. Obviously with so many classes its rare to find a moment or script where all are used at the same time, but imagine a system where all business logic is store in objects, the outcome would be various files and only a handful being used at the same time, but without autoload you would have to include all these files anyway, or resort to including the files in each action script, a handful of work and a possible mess.
The final outcome was Page with manual includes: 0,0366659164429 seconds Page with __autoload: 0,0239880084991 seconds
Conclusion
In a system with a central file, and where we would like to have less headaches, or work including each individual class, autoload makes a big difference, and it should be taken advantage of. I haven’t as of yet found any meaningful downside to using it that could nagativelly impact the final outcome. If you know of any, please let me know.