Cache in a Map
One of the ways to do this is to store a class cache by name in a 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 file name without the extension.
Example, given a call list_classes('classes')
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'
}
Anyway, creating this global cache, just use it in your method of autoload.
However, there will be a problem 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 the array
and issue an error or warning.
Also, if there are too many folders and directories, this may affect a little the performance of the script, but will be done only once. So whether or not this technique is worth it depends on how many times the autoload 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 array
will dictate the priority of the search.
Here is an example (based on ONLY):
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 directory array could be automatically loaded with an algorithm similar to the previous one:
$array_paths = glob(dirname(__FILE__).'/../*', GLOB_ONLYDIR);
This way, it is not necessary to go through all the subdirectories, but with each class load you will need to look at the file system.
Nomenclature standard
Another technique used by some frameworks, such as Zend Framework
is to put a underline in the class name to represent the path from a base directory. For example, the class Animal_Cachorro
fricaria in the directory /Animal
.
Follow an example code (based on ONLY):
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 direct and best performing method as it is only made a cess to the file system.
However, from my point of view, it "defiles" the class names. It does not seem to me good practice to mix the directory structure with the names of its classes just to facilitate the construction of frameworks and method utilities.
Why not use Autopload? Very simple and practical, not to mention that your code will be within a standard (PSR).
– Brayan
@Hello Brayan, it’s an idea. If you can elaborate an answer with this solution and an example of how it works!
– Zuul
@Zuul, I’ve been following the updates of this question. There are plenty of options. If none of the answers pleased you, it wouldn’t be good to give us a feedback on that so that we can improve them?
– utluiz
@utluiz In fact, only today I am testing each of the options presented to see which "behaves" best, I will vote and assign the bonus within 3 days ;) Until then, or at least without completing the tests, I cannot say that the conditions for this are not met!
– Zuul