Я на самом деле пытаюсь создать структуру 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 ; } });
Он работает хорошо, однако я уверен, что есть еще один способ сделать все проще. Может ли кто-нибудь предложить мне, как я могу сделать этот код лучше или проще / что гуру используют в этой ситуации?
Для того, чтобы люди, которые могут получить ответ от получения устаревшей информации, я обновил ее в отношении новейших стандартов автозагрузки 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's 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's 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
не будет автоматически Front_controller.php
, как и следовало ожидать.
Код ниже поможет. Но я советую вам проверить пространство имен.
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; } } });