A few months ago I proposed a way to efficiently use __autoload() together with a class indexer. To my surprise, quite some people started using it and provided me with bug reports. I rewrote most of the original code, eliminated all known bugs and have been testing it for the last month. So here’s a new version with some improvements:
- Added ability to scan include directories, too
- Using SPL RecursiveDirectoryIterator for the indexer/scanner
- Optimized SmartLoader::load(). It now takes < 1 ms to complete (with inclusion) on my machine
- Windows support through DIRECTORY_SEPARATOR constant
- More information in index file headers, like:
* Created by: /usr/local/php5/lib/php/SmartLoader/SmartLoader.class.php
* Created at: Thu, 06 Apr 2006 23:54:48 +0200
* Scanned: 134 directories and 402 files in 1.15 seconds.
Backwards compatibility?
Robert Schmelzer dug up the most remarkable bug. As of PHP 5.1.2 this piece of code won’t work anymore:
preg_match_all('/hand/', 'Talk to the hand!', $result = array()));
The $result variable will be empty unless I remove the “= array()”. Why?
Of course, one could argue about how much sense initializing the result as array makes. From my point of view it’s about making the code more readable by showing that I’m passing an empty array to be filled. I suppose Derick, on the other hand, would call it “doing something silly“. ;)
How to use
The best way to use SmartLoader is to put the SVN trunk’s contents into your include directory (don’t forget write access for SmartLoader/indexfiles). After that you can easily set it up in your scripts by adding these two lines:
require('smartloader.php');
SmartLoader::addIncludeDir(dirname(__FILE__).'/../'); /* (or just the document root) */
I strongly recommend prefixing your classes, especially when using the handy include directory scanning or else you’ll get name collisions. Maybe PHP namespaces will solve this problem somewhen.






April 7th, 2006 at 1:01 pm
I have been using it for a while and it is very useful. The biggest annoyance is when a class is not found - in a big system, sometimes you don’t know *where* it was called.
April 7th, 2006 at 7:45 pm
haha - you’ve re-invented include_path ;)
no more wondering where a file is included from, you just have to read the mind of the author and hope he hasnt hidden away the SmartLoader call in some obscure include file.
April 7th, 2006 at 10:05 pm
> the most remarkable bug
In case anyone was wondering, this does work:
class Test { function __construct($a) { print_r($a); } } $test = new Test($a = array('hello'));April 9th, 2006 at 3:19 am
Why not replace the $GLOBALS[] usage with a static property as it should be private to the class.
April 9th, 2006 at 3:32 am
Also it might be good to use the for loop instead of foreach as I remember it being *much* faster in the PHP benchmark I read somewhere…
$size=sizeof($something)
for($i=0; $i
April 9th, 2006 at 6:45 am
Great, isn’t it? Let’s call it include_path on crack! ;)
I can’t put it into SmartLoader itself because it is defined somewhere else and I can’t define a class (or parts of it) twice. I could put it into some SmartLoaderIndex::index variable but that’s just another (and fashionable) way to make it global.
For-loops are about 3 times faster, that’s correct. But don’t make the mistake to write something like this:
The sizeof function would be executed for every iteration, which makes a loop about 10x slower than a foreach.
However, there are no performance-critical loops in SmartLoader. Most of the time (while indexing, which happens once per software revision!) is being used for preg_match_all (I could try to improve the pattern’s performance) and PHP function calls (which are horribly slow). You can’t use for-loops on associative arrays, either.
April 12th, 2006 at 12:42 am
and then there is the obvious performance booster:
$total = sizeof($array);
for($i=0; $i
April 12th, 2006 at 12:44 am
sorry
$total = sizeof($array); for($i=0; $iApril 13th, 2006 at 12:40 am
I hope this isn’t the case. I used to think that until I ran some tests a while back and it’s only executed on the first iteration. My test was something like
$test = array(…..);
for ($i=0; $i”prior” to adding more elements inside it.
I believe you only experience said effect while using something like while() and each().
April 13th, 2006 at 6:27 am
mrsmiley, you can easily check that with the following code (or just XDebug/Cachegrind):
April 19th, 2006 at 9:50 pm
An optimizer might be able fix the loop, but vanilla PHP doesn’t have an optimizer. I always write for-loops as this to be sure :
for ($i=0, $l=count($a); $i < $l; ++$i) { }Using ++$i rather than $i++ also saves an internal buffer.
May 25th, 2006 at 1:43 am
Maarten,
I found a little ‘quirk’ in the regex pattern, in that it matches commented code.
Not only would this be an issue if it thought it could find a class that had been commented out, but also you could inadvertantly overwrite the location of a real class in the index file while writing examples in another file that was scanned elsewhere in the indexing process.
E.g.
File 1:
[code]/**
* FooBar class
*
* Not bothered what I write here, as it’s a comment…
*
* Example Usage:
*
* class MyClass extends FooBar {}
*
*/
[/code]
File 2:
[code]class MyClass
{
$foo = bar;
}[/code]
The index thinks the class can be found in File 1, rather than File 2.
Matt.
May 25th, 2006 at 1:45 am
Oops, let’s try that again….
(why no preview for comments???)
Maarten,
I found a little ‘quirk’ in the regex pattern, in that it matches commented code.
Not only would this be an issue if it thought it could find a class that had been commented out, but also you could inadvertantly overwrite the location of a real class in the index file while writing examples in another file that was scanned elsewhere in the indexing process.
E.g.
File 1:
/** * FooBar class * * Not bothered what I write here, as it’s a comment… * * Example Usage: * * class MyClass extends FooBar {} * */File 2:
class MyClass { $foo = bar; }The index thinks the class can be found in File 1, rather than File 2.
Matt.
September 29th, 2006 at 1:04 am
Probably extremely late to the party…
Mincer:
> I found a little ‘quirk’ in the regex pattern,
> in that it matches commented code.
My concern as well, though it’s easily fixed with a little token_get_all(), T_CLASS and T_INTERFACE.
October 1st, 2007 at 7:27 pm
Hmm, the download link ist not available anymore, can i get the smartloader update elsewhere?
December 22nd, 2007 at 1:21 am
Download link still ain’t available, I also would like to try out this new version. Especially since you’ve mentioned the DIRECTORY_SEPERATOR, which probably was why it wasn’t working for me before on Windows.