Автозагрузчик классов используется, обычно, в более-менее крупном проекте или таком, который имеет перспективы развития в дальнейшем. В настоящее время, при создании таких проектов, особой популярность пользуется концепция MVC (Model-View-Controller: модель-вид-контроллер). Поэтому рассмотрим способ организации автозагрузки в рамках данной структуры. Так же, в реальных проектах, желательно использовать пространства имен для избежания дублирования имен классов, констант и др.

Конечно, если вы используете Composer для установки различных php библиотек, фреймворков и расширений, грех не воспользоваться его автозагрузчиком, про который я писал тут. Но предположим что Composer вы, по каким-то причинам, не можете использовать.

Файл автозагрузчика классов (autoload.php) подключается в точке входа (файл index.php). Сам класс автозагрузчика регистрируется в начале запуска приложения после выполнения метода run() с помощью функции spl_autoload_register(), которая вызывает метод autoload() класса ClassLoader. Автозагрузчик классов вызывается автоматически каждый раз при вызове любого класса, который не был объявлен.

Для работы автозагрузчика, каждый подключаемый класс должен быть в отдельном php-файле, который называться должен аналогично названию класса. Например класс Config должен находиться в файле Config.php

Автозагрузчик прежде всего ищет запрашиваемый класс в карте классов, которая представляет собой ассоциативный массив, находящийся в отдельном файле vendor/classes.php. Он содержит названия классов в виде свойств массива и путь к файлам данных классов в виде значений. Например:
'Config' => 'library/Config.php'.
В карту сайта следует включить служебные классы, которые нужны для работы приложения. Карта классов используется для ускорения загрузки.

Не найдя класс в карте классов, вызывается дополнительный метод, который ищет файл класса в массиве дирректорий public static $dir. В данный массив следует включить названия основных папок, которые предназначены для создания в них файлов классов по ходу работы над созданием сайта.

При использовании концепции MVC, это прежде всего controller и model.

После использования обоих попыток подключить требуемый класс, проверяется объявлен ли он. И если нет – генерируется исключение с выводом соответствующего сообщения.

Структура каталогов/файлов:
- config
       - db.php
- vendor
       - autoload.php
       - classes.php
       - main.php<span class="redactor-invisible-space"></span>
- controller
       - MyController.php
- model
- view
- index.php

Рассмотрим код основных файлов.
index.php:
<?php
define("ROOT_DIR",dirname(__FILE__).'/');

require_once "vendor/autoload.php"; //автозагрузчик классов
require_once "vendor/main.php"; //основной класс приложения

$application = new Application();    
$application->run();
В данном файле (точке входа) первым делом, создаем константу ROOT_DIR, которая будет использоваться для указания пути к корню приложения.
Далее загружаем файлы с классами, создаем объект приложения и вызываем метод, который вызывает и подключает все нужные для работы классы/методы, а прежде всего автозагрузчик классов.




vendor\autoload.php
<?php
class ClassLoader {

    public static $classMap;
    public static $addMap = array();
    public static $dir = [
            'controller',
            'model',
    ];
    
    //Добавить класс к карте классов
    public static function addClassMap($class = array()){
            self::$addMap = array_merge(self::$addMap, $class);
        }

    public static function autoload($className){

            //подключаем и сохраняем карту классов. Добавляем пользовательские классы.
            self::$classMap = array_merge(require(__DIR__ . '/classes.php'), self::$addMap);
    
           //Ищем в карте классов
            if (isset(self::$classMap[$className])) {
                $filename = self::$classMap[$className];
                include_once ROOT_DIR . $filename; 
            //Ищем в папках
            } else {
                self::library($className);
            }

            //Проверка был ли объявлен класс
            if (!class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) {
                throw new Exception('Невозможно найти класс '.$className);
            }    
    }
    
    public static function library($className){
            foreach (self::$dir as $d){
                $filename = ROOT_DIR . $d . '/'. $className . ".php";
                if (is_readable($filename)) {
                    require_once $filename;
                }
            }   
        }
    
}
Это класс самого автозагрузчика, который ищет файл требуемого класса сначала в карте классов, а не найдя в списке директорий, указанных в свойстве $dir. Так же класс генерирует исключение в случае, если затребованный класс подключить не удалось.

Сама карта классов должна быть в таком формате (файл vendor\classes.php):
<?php
return [
    'ConfigDb' => 'config/db.php',
    'my\widgets\Menu' => 'widgets/Menu.php', //можно использовать пространства имен
    'my\helpers\Html' => 'helpers/Html.php',
];

vendor\main.php
<?php 

class Application {
    
    public function run(){
            $this->Loader();
            //...
    }
    
    public function Loader(){
        spl_autoload_register(['ClassLoader', 'autoload'], true, true);

        try{
            $config = new ConfigDb();
            echo $config->get('database', 'login'); //mylogin

            echo MyController::$params; //KSL

           //Пример добавления каталога в автозагрузчик классов
            //ClassLoader::$dir[] = 'view';

            //Пример добавления класса MyClass к карте классов
            //ClassLoader::$addMap['MyClass'] = 'folder/MyClass.php';

        } catch (Exception $e){
            echo '<h2>Внимание! Обнаружена ошибка.</h2>'.
            '<h4>'.$e->getMessage().'</h4>'.
           '<pre>'.$e->getTraceAsString().'</pre>';
            exit;
        }
    }
    
}
Это основной класс приложения. В данном случае при его запуске из index.php, метод run() первым делом вызывает метод Loader(), который регистрирует наш автозагрузчик классов с помощью функции spl_autoload_register(), в которой указывается класс и метод самого автозагрузчика. В этот метод, данная функция, передает название вызываемого класса (или класса, экземпляр которого мы пытаемся создать).
Для примера, тут создается объект класса ConfigDb с вызовом его метода get(), возвращающего некоторые данные. Данный класс у нас прописан в карте классов и таким образом проверяем работу автозагрузчика по поиску в карте классов.
После этого, проверяем автозагрузчик на предмет поиска в списке указанных для этого директорий. Для этого вызываем статическое свойство $params класса MyController. Данный класс размещен в папке controller, которая включена в массив свойства $dir, а значит класс подключится на втором этапе поиска с выводом значения запрашиваемого свойства.

Чтобы была возможность протестировать и не набирать все вручную - выкладываю архив файлов. Можно запустить на локальном сервере. При этом на экране будет выведен результат вызова двух методов, которые использованы для проверки автозагрузчика классов.