Recursive autoloader to find PHP files I created a small working autoloader based on some of the answers and ideas found on Stack Exchange (I lost the reference). However, I don't know much about PHP (I mainly know C, a bit C++ and Java). I'm trying to create a small MVC website for school project using my own templates and JavaScript as well. I mainly created this autoloader to include class files (I'm not sure if any other files can be included with autoloader too).

Can you please check this autoloader and give your insight on what can be done better and if there are any shortcomings?

It's important to know that I don't use namespaces currently because it would overcomplicate things.

&lt;?php


    class Autoload
    {
        private $allFiles = array();

        public function __construct() {

            $this-&gt;findDir(__DIR__, $this-&gt;allFiles);
            spl_autoload_register(array($this, 'classLoader'));
        }

        private function classLoader($class) {

            if (class_exists($class, false)) {
                return true;

            } else {
                $this-&gt;includeClass($this-&gt;allFiles, $class);
                // should I return here true as well?
            }
        }

        private function findDir($currDir, &amp;$files) {

            $dirsInCurr = glob($currDir . "/*", GLOB_ONLYDIR);
            $this-&gt;findFiles($currDir, $files);

            //recursive call
            foreach ($dirsInCurr as $dir) $this-&gt;findDir($dir, $files);
        }

        private function findFiles($dir, &amp;$files) {

            $fPaths = glob($dir . "/*.php");
            foreach ($fPaths as $f) $files[] = $f . "\n";

        }

        private function includeClass($files, $class) {

            foreach ($files as $f) {
                if (strpos($f, strtolower($class) . ".php")) require_once trim($f);
            }
        }
    }

    $autoload = new Autoload();

?&gt;
There are several ways to improve the code.
Let's start with the constructor.

You should not make any assumptions about the place of a file in the current file system, because that makes later changes very hard and it hurts reusability.
So get rid of the __DIR__ constant and send the directory of the classes as an argument to the constructor instead.

Registering callbacks and finding a file are two very different tasks. They don't belong to the same class. So register a method of an instance of the autoloader from the outside instead, and remove the call to spl_autoload_register() from your class.

You should use namespaces for all of your classes, interfaces and traits. This prevents collisions in case that you want to use other peoples code in your project later. Add a $namespace argument to your constructor.


In the end, your constructor shouldn't do more than setting up private members, maybe add some preparation for these. Example:
/**
 * Autoload constructor.
 *
 * @param string $namespace Pass the namespace unescaped.
 * @param string $dir
 */
public function __construct( $namespace, $dir )
{
    // Make sure it ends with a '\'.
    $namespace       = rtrim( $namespace, '\\' ) . '\\';
    $this-&gt;namespace = $namespace;
    $this-&gt;length    = strlen( $namespace );
    $this-&gt;dir       = rtrim( $dir, '/' ) . '/';
}

Now, to the actual class loader classLoader().

I wouldn't call it classLoader, because it will load traits and interfaces too. Just call it load(), that's clear enought for a class named Autoload. :) And because you will register and test it directly, make it public.

Do not return a value in that method. If you find a matching file, just include it and stop, return nothing otherwise. PHP will figure the rest out for you.

class_exists() is pointless here, because that method will be called only if the class/trait/interface doesn't exist yet. Just remove it.

The private methods called from that &quot;parent&quot; method don't deal with namespaces, and they are too slow. You don't need glob() here. (On a side note GLOB_ONLYDIR is not available on Solaris/Sun OS, use that constant only if portability is not a concern for your code.)
Figure out the correct complete file path first, then check if that file exists and is readable! The latter is important, because you cannot rely on the fact that you can actually include all existing files.


So that method may be reduced to something like this:
/**
 * @param string $search
 * @return void
 */
public function load( $search )
{
    if ( strncmp( $this-&gt;namespace, $search, $this-&gt;length ) !== 0 ) {
        return;
    }

    $name = substr( $search, $this-&gt;length );
    $path = $this-&gt;dir . str_replace( '\\', '/', $name ) . '.php';

    if ( is_readable( $path ) ) {
        require $path;
    }
}

Finally to the registration. As you can see, you can reuse the class now to find files in different directories mapped to a namespace. Let's say all of your own files are living under the namespace CodeReview in the directory src/ (this is a convention in PHP).
In the main file of your application, you can include the Autoloader and register its load() method now like this:
require __DIR__ . '/src/Autoload.php';
spl_autoload_register( [ new Autoload( 'CodeReview', __DIR__ . '/src/' ), 'load' ] );

Now let's say, you have a class Response living under namespace CodeReview\Http.
namespace CodeReview\Http;

class Response {}

It should be placed under /src/CodeReview/Http/Response.php.
You can create a new instance now either with:
new CodeReview\Http\Response;

… or you put a use statement at the top of the file that is creating that instance:
use CodeReview\Http;

new Response;

Your class is much simpler now, you can test it, map it to different directories and namespaces, use it in different projects, and put it in any place you like.