Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best solution for __autoload

Tags:

oop

php

autoload

As our PHP5 OO application grew (in both size and traffic), we decided to revisit the __autoload() strategy.

We always name the file by the class definition it contains, so class Customer would be contained within Customer.php. We used to list the directories in which a file can potentially exist, until the right .php file was found.

This is quite inefficient, because you're potentially going through a number of directories which you don't need to, and doing so on every request (thus, making loads of stat() calls).

Solutions that come to my mind...

-use a naming convention that dictates the directory name (similar to PEAR). Disadvantages: doesn't scale too great, resulting in horrible class names.

-come up with some kind of pre-built array of the locations (propel does this for its __autoload). Disadvantage: requires a rebuild before any deploy of new code.

-build the array "on the fly" and cache it. This seems to be the best solution, as it allows for any class names and directory structure you want, and is fully flexible in that new files just get added to the list. The concerns are: where to store it and what about deleted/moved files. For storage we chose APC, as it doesn't have the disk I/O overhead. With regards to file deletes, it doesn't matter, as you probably don't wanna require them anywhere anyway. As to moves... that's unresolved (we ignore it as historically it didn't happen very often for us).

Any other solutions?

like image 791
tpk Avatar asked Dec 11 '08 15:12

tpk


1 Answers

I've also been playing with autoload for quite some time, and I ended up implementing some sort of namespaced autoloader (yes, It works also for PHP5.2).

The strategy is quite simple: First I have a singleton class (loader) which has a call that simulates import. This call takes one parameter (the full class name to load) and internally calculates the file name it was called from (using debug_backtrace()). The call stores this information in an associative array to use it later (using the calling file as the key, and a list of imported classes for each key).

Typical code looks like this:

<?php

    loader::import('foo::bar::SomeClass');
    loader::import('foo::bar::OtherClass');

    $sc = new SomeClass();

?>

When autoload is fired, the full class name that was stored in the array gets transformed to a real filesystem location (double colons are replaced with directory separators), and the resulting filename is included.

I know that It's not exactly what you were asking for, but it may solve the directory traversal issue, as the loader directly knows where the file exactly is (with the added feature that you could have your classes organized in directories, with no apparent performance penalty).

I could provide you some working examples, but I'm too shy to show my crappy code to the public. Hope the above explanation was useful...

like image 96
azkotoki Avatar answered Oct 19 '22 16:10

azkotoki