Как использовать spl_autoload_register для множественных diectories в PHP?

Я на самом деле пытаюсь создать структуру MVC для себя, однако у меня возникают проблемы с Autoload. Это не проблема на самом деле, но я хотел бы спросить гуру, как они используют функцию spl_autoload_register, когда есть разные каталоги.

Допустим, что у нас есть следующие каталоги:

Controllers
Libs
Models

Каждая папка содержит разные классы, например:

Controllers:
   Main.php
   File.php
   About.php
Libs:
   Main.php
   Front_controller.php
Models:
   Index.php
   File.php
   Login.php

Вы можете заметить, что некоторые имена файлов могут быть найдены с тем же именем в разных каталогах. Хорошо, так вот что я пробовал до сих пор:

spl_autoload_register(function ($class) { 

    $pathContorllers = 'Controllers/' . $class . '.php';
    $pathLibs = 'Libs/' . $class . '.php';
    $pathModels = 'Models/' . $class . '.php';

    if (file_exists($pathContorllers)) {
        require_once $pathContorllers;
    } elseif (file_exists($pathLibs)) {
        require_once $pathLibs;
    } elseif (file_exists($pathModels )) {
        require_once $pathModels ;
    }
});

Он работает хорошо, однако я уверен, что есть еще один способ сделать все проще. Может ли кто-нибудь предложить мне, как я могу сделать этот код лучше или проще/что гуру используют в этой ситуации?

Ответ 1

Для того, чтобы люди, которые могут столкнуться с этим ответом, получая устаревшую информацию, я обновил ее в отношении последних стандартов автозагрузки PSR. Первоначальный ответ был сохранен для исторических целей и для тех, кто интересуется только автозагрузчиком PSR-0.

Обновленный ответ

PHP-FIG официально отказался от стандарта PSR-0 в пользу альтернативного автозагрузчика, PSR-4. Хотя в обоих аспектах они одинаковы, в других они также очень разные. (Например: обработка символов подчеркивания в именах классов.)

Вы можете подумать про себя: "Сейчас я использую PSR-0, и он отлично работает". Истина в том, что PSR-0 все равно будет работать нормально для определенных проектов. Это особенно актуально, если обратная совместимость с пакетом, который не использует пространства имен. PSR-0 по-прежнему является достойным принципом автозагрузки, но имеет свои недостатки.

Конечно, если есть одна вещь, которая является константой с программированием, это значит, что код в конечном итоге изменяется, и методы программирования продолжают развиваться. Сегодня вы можете сделать себе одолжение, подготовившись к завтрашнему дню. Поэтому, если вы только начинаете проект или пытаетесь перенести проект на более новую версию PHP, которая может использовать пространства имен, вам следует серьезно подумать об использовании автозагрузчика PSR-4.

Также стоит отметить, что если вы разрабатываете проект, который не использует пространства имен, то PSR-4 не относится к вам. В этом случае применяется PSR-0 или ваш собственный автозагрузчик.


Оригинальный ответ

Если вы хотите пойти с пространствами имен в своих классах, то маршрут PSR-0 - довольно хороший способ автозагрузки. В основном ваше пространство имен представляет структуру каталогов, и классы могут быть загружены на основе соглашения.

Если метод PSR-0 не удовлетворяет всем вашим потребностям (или не играет хорошо с существующим кодом), вы можете добавить дополнительные функции с помощью spl_autoload_register, и PHP будет проходить через них один за другим в попытке классов нагрузки.

Использование примера:

Прежде всего, если вы не знакомы с пространствами имен в PHP, то вам будет полезно ознакомиться с руководством по этому вопросу в PHP. Сначала они могут быть немного запутанными, но их преимущества стоят первоначальной путаницы.

Итак, я сказал, что PSR-0 работает, связывая ваши пространства имен с вашей структурой каталогов. Позвольте использовать ваши каталоги для примера. У вас в корневой папке (где бы она ни находилась):

Project directory:  <- Let call this directory "MyProject"
    Controllers:
       Main.php
       File.php
       About.php
    Libs:
       Main.php
       Front_controller.php
    Models:
       Index.php
       File.php
       Login.php
index.php <- Let say this is your entry point file, this is where you will be autoloading stuff from.

Теперь посмотрим на ваш контроллер Main.php. Две вещи, о которых следует помнить, это то, что имя класса должно быть именем файла, а пространство имен для этого класса - путь к каталогу этого файла. Поэтому Main.php должен выглядеть примерно так:

<?php

namespace MyProject\Controllers;

class Main {

    //Field vars, contructor, methods, etc. all go here.

}

?>

Вы бы сделали то же самое для своей модели Login

<?php

namespace MyProject\Models;

class Login {

    //Field vars, contructor, methods, etc. all go here.

}

?>

Теперь в вашем файле index.php (в корневом каталоге - MyProject) вы сделаете свой вызов на spl_autoload_register и передадите его автозагрузчику PSR-0.

spl_autoload_register( function ($className) {
    $className = ltrim($className, '\\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strrpos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
});

//Now you can make your call to your objects without a bunch of include/require statements

$main = new \MyProject\Controllers\Main();  //Instantiates your 'Main' controller
$login = new \MyProject\Models\Login();   //Instantiates your 'Login' model

Надеюсь, это поможет лучше понять это, и снова, если вы не хотите использовать пространства имен, вы всегда можете просто добавлять добавления в стек автозагрузки SPL. У вас может быть 10 различных автозагрузчиков, если вы хотите, и PHP будет проходить через них один за другим (в том порядке, в котором вы их определили), используя каждую функцию, чтобы попытаться загрузить класс. Тем не менее, несколько автозагрузчиков, основанных на соглашениях, немного чище и более предпочтительный. Также имейте в виду, что автозагрузчик переводит обе разделители пространства имен \ и подчеркивает _ как разделитель каталога. Таким образом, ваш Front_controller.php не будет автоматически загружаться, как и следовало ожидать.

Ответ 2

Код ниже поможет. Но я советую вам проверить пространство имен.

spl_autoload_register ( function ($class) {

$sources = array("Controllers/$class.php", "Lib/$class.php ",  "Models/$class.php " );

    foreach ($sources as $source) {
        if (file_exists($source)) {
            require_once $source;
        } 
    } 
});