1
\$\begingroup\$

After doing much reading of the PHP docs and trying out other developers' autoloader code, below is what I've come up with for an autoloader. It is working as expected so far. Posting the code here to gather review/feedback from peers. Here are some questions that come to mind -

  • How can it be improved?
  • Are there any potential issues?
  • Are there any ways to make it more concise without sacrificing readability?
// ROOT is used in multiple places in the app, thus the constant
define('ROOT', $_SERVER['DOCUMENT_ROOT'] . '/MyApp/');

# autoloader
// recurses through project directory and builds associative array with file name as key and fully qualified file name as value (restrictions: file names end with .php, exclude index.php)
// autoloader function loads class files by matching class name to file name key in array to get path value
// note: RecursiveIteratorIterator returns an associative array with fully qualified file name as key and SplFileInfo Object as value

$projectDirectory = ROOT;
$ignore = ['.git','_Logs'];

$directory = new RecursiveDirectoryIterator($projectDirectory, RecursiveDirectoryIterator::SKIP_DOTS);
$directory = new RecursiveCallbackFilterIterator($directory, fn($current) => !in_array($current->getFilename(), $ignore));
$objects = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::LEAVES_ONLY);

foreach (iterator_to_array($objects) as $fullFileName => $splFileInfoObject) {
    $fileNameWithExtension = $splFileInfoObject->getfileName();
    if (substr($fileNameWithExtension, -4) == '.php' && $fileNameWithExtension != 'index.php') {
        $fileName = pathinfo($fileNameWithExtension, PATHINFO_FILENAME);
        $files[$fileName] = $splFileInfoObject->getPathname();
    }
}

// exit('<pre>' .  print_r($files, 1) . '</pre>');

define('FILES', $files);

spl_autoload_register(fn($className) => require_once(FILES[$className]));

EDIT - The directory structure of this app is:

  • Config
  • Modules
  • Utilities

Modules is where the business related files live. The Modules directory has a lot of activity during development with new subfolders being added frequently as new parts of the app are built. Thus the desire for an autoloader that can just recognize new subfolders and files.

Also, this app is not namespaced.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Efficiency, Efficiency, Efficiency!

I don't know how big your applications are, but I wouldn't want to recursively scan all the files in my applications, every time a PHP script wants to execute. Want to do a tiny AJAX call? Scan... scan... It just isn't efficient. A project can have many autoloaders. Just imagine they would all work like you propose.

The only task an autoloader has is to get the script, containing a single class, as quickly and efficiently as possible. This is a simple task, it's code should be equally simple.

Just put all the class files in one location, use the name of a class to find a file, and you're done. If the autoloader didn't find the wanted file then move on to the next autoloader. Perhaps that's a bit boring, but it works, so why change it?

Yes, it is nice that you can scan and process all the files in your project with proper iterators, but this is not the place to use those.

PS: This might come over as a harsh review, but it is written with the best intentions. I'm also glad you prefer readability over conciseness.

\$\endgroup\$
10
  • \$\begingroup\$ Valuable input. Regarding "...put all the class files in one location..." do you mean put all the class files within a single directory in the project? The reason for changing my autoloader to look through the project directory is because there are several subfolders in which class files are stored. \$\endgroup\$
    – knot22
    Feb 27 at 12:59
  • \$\begingroup\$ Question - since FILES is outside of the anonymous function used in spl_autoload_register(), doesn't the directory scan occur just once, when the file in which it's contained, Config.php, is included by the calling file? \$\endgroup\$
    – knot22
    Feb 27 at 13:20
  • 1
    \$\begingroup\$ @knot22 1. Yes, all in a single directory. You can put them in several sub-folders, as long as you have a method to decide which class resides in which sub-folder. Often namespaces are used for this, the namespace is part of the class-name you get in the spl_autoload_register() callback function. 2. No, every time a PHP script is executed and you include the code from your question, you are recreating FILES all over again. You could store its content somewhere, and reuse that, but you don't. \$\endgroup\$ Feb 27 at 14:28
  • 1
    \$\begingroup\$ Oh, one other way you could work with multiple class folders in your app is to work with multiple autoloaders, of course. I know, in the end this also isn't very efficient, but you could put the most used classes at the front of the autoloader queue. \$\endgroup\$ Feb 27 at 18:20
  • 1
    \$\begingroup\$ @knot22: The value of static variables is only remembered until the script, in which they were created, stops executing. To remember things, from one script executing to another, you need to use something more permanent, like a file or database. The latter is basically also a file. \$\endgroup\$ Mar 9 at 6:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.