Cache on a Map
One way to do this is to store a class cache by name in array
. I did a basic implementation:
function list_classes($dir, $array = array()){
$files = scandir($dir);
foreach($files as $f){
if($f != '.' && $f != '..'){
if (strcmp(pathinfo($f)['extension'], 'php') == 0) {
$array[basename($f, '.php')] = $f;
} else if(is_dir($dir.'/'.$f)) {
list_classes($dir.'/'.$f, $array);
}
}
}
return $array;
}
$classes_cache = list_classes(dirname(__FILE__));
var_dump($classes_cache);
The above code recursively lists the files .php
of the current directory, including subdirectories and stores in a array
(or map) whose index (or key) is the filename without the extension.
Example, given a list_classes('classes')
call from main.php
:
/
main.php
/classes
Class1.php
Class2.php
/other_classes
Class3.php
The result of the array would be:
{
'Class1' => 'Class1.php',
'Class2' => 'Class2.php',
'Class3' => 'other_classes/Class3.php'
}
Finally, by creating this global cache, just use it in your autoload method.
However, there will be problems if there are files with the same name in different directories. In this case, it would be interesting to add a check if the item already exists in array
and issue an error or warning.
In addition, if there are too many folders and directories, this can affect script performance a bit, but it will only be done once. So whether or not this technique is worth it depends on how many times the autoload method will be called.
Directory List
A second approach is to create a array
of directories and search if the class exists in each of them. Note that the order of array
will dictate search priority.
Here's an example (based on SO ):
function __autoload($class_name) {
$array_paths = array(
'classes/',
'classes/site'
);
foreach($array_paths as $path) {
$file = sprintf('%s%s/class_%s.php', dirname(__FILE__), $path, $class_name);
if(is_file($file)) {
include_once $file;
}
}
}
The array of directories could be automatically loaded with an algorithm similar to the one above:
$array_paths = glob(dirname(__FILE__).'/../*', GLOB_ONLYDIR);
In this way, it is not necessary to go through all the subdirectories, but with each class load it will be necessary to look at the filesystem.
Naming Pattern
Another technique used by some frameworks, such as Zend Framework
, is to place an underline in the class name to represent the path from a home directory. For example, the class Animal_Cachorro
would rub in the /Animal
directory.
Here is a sample code (based on SO ):
function __autoload($class_name) {
$filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)).'.php';
$file = dirname(__FILE__).'/'.$filename;
if (!file_exists($file)) return FALSE;
include $file;
}
This is the most straightforward and best performing method, as only one file system crash is done.
However, from my point of view, it "dirty" the name of the classes. It does not seem good practice to mix the directory structure with the names of your classes just to make it easier to build frameworks and utilities.