Как и большинство веб-разработчиков в эти дни, я полностью наслаждаюсь преимуществами надежной архитектуры MVC для веб-приложений и сайтов. При выполнении MVC с PHP автозагрузка, очевидно, очень удобна.
Я стал поклонником spl_autoload_register
просто определяя одну __autoload()
, поскольку это, очевидно, более гибко, если вы включаете различные базовые модули, каждый из которых использует собственную автозагрузку. Тем не менее, я никогда не чувствовал себя прекрасно в функциях загрузки, которые я пишу. Они требуют много проверки строки и сканирования каталогов, чтобы искать возможные классы для загрузки.
Например, допустим, у меня есть приложение, которое имеет базовый путь, определенный как PATH_APP
, и простую структуру с каталогами, названными models
, views
и controllers
. Я часто использую структуру именования, в которой файлы называются IndexView.php
и IndexController.php
внутри соответствующего каталога, а модели по умолчанию вообще не имеют конкретной схемы. У меня может быть функция загрузчика для такой структуры, которая регистрируется с помощью spl_autoload_register
:
public function MVCLoader($class) { if (file_exists(PATH_APP.'/models/'.$class.'.php')) { require_once(PATH_APP.'/models/'.$class.'.php'); return true; } else if (strpos($class,'View') !== false) { if (file_exists(PATH_APP.'/views/'.$class.'.php')) { require_once(PATH_APP.'/views/'.$class.'.php'); return true; } } else if (strpos($class,'Controller') !== false) { if (file_exists(PATH_APP.'/controllers/'.$class.'.php')) { require_once(PATH_APP.'/controllers/'.$class.'.php'); return true; } } return false; }
Если после этого он не будет найден, у меня может быть другая функция для сканирования подкаталогов в каталоге моделей. Тем не менее, все if / else-ing, проверка строк и сканирование каталогов кажутся мне неэффективными, и я хотел бы улучшить его.
Мне очень любопытно, какие стратегии наложения имен и автозагрузки могут использовать другие разработчики. Я ищу конкретные методы для эффективной автозагрузки, а не альтернативы автозагрузке.
Это то, что я использовал во всех своих проектах (снятых прямо из источника последнего):
public static function loadClass($class) { $files = array( $class . '.php', str_replace('_', '/', $class) . '.php', ); foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path) { foreach ($files as $file) { $path = "$base_path/$file"; if (file_exists($path) && is_readable($path)) { include_once $path; return; } } } }
Если я ищу SomeClass_SeperatedWith_Underscores, он будет искать SomeClass_SeperatedWith_Underscores.php, за которым следует SomeClass / SeperatedWith / Underscores.php, внедренный в каждую директорию в текущем пути include.
EDIT: Я просто хотел потушить там, что я использую это для эффективности в разработке, и не обязательно время обработки. Если у вас есть PEAR на вашем пути, то с этим вы можете просто использовать классы и не включать их, когда они вам понадобятся.
Я стараюсь, чтобы мои классы были в иерархии каталогов, с подчеркиваниями, разбивающими пространства имен … Этот код позволяет мне сохранять структуру файла красивой и аккуратной, если захочу, или вводить быстрый файл класса без вложенных каталогов, если я хочу (для добавив один класс или два в библиотеку, на которую она ответила, но не часть проекта, над которым я сейчас работаю.)
Я приземлился на это решение:
Я создал один скрипт, который пересекает мою библиотеку библиотеки классов (которая содержит вложенные папки для отдельных модулей / систем) и анализирует содержимое файла, ищущего определения классов. Если он находит определение класса в php-файле (довольно простой шаблон регулярного выражения), он создает символическую ссылку:
class_name.php -> actual/source/file.php
Это позволяет мне использовать единую простую функцию автозагрузки, которая требует только имени класса и пути к основной папке symlink и не требует каких-либо манипуляций по пути / строкам.
Самое приятное то, что я могу полностью изменить исходный код или добавить новую подсистему и просто запустить сценарий генерации ссылок, чтобы все было загружено автоматически.
Если вам нужна эффективность, вы не должны использовать функцию автозагрузки вообще. Функция автозагрузки является ленивой. Вы должны предоставлять явный путь к вашим включенным файлам при их включении. Если ваша функция автозагрузки может найти эти файлы, вы можете запрограммировать их, чтобы найти их явно. Когда вы работаете над частью представления и загружаете новый класс представления, позволяя функции автозагрузки обрабатывать его, он сначала предполагает, что ваш класс является классом модели? Это неэффективно. Вместо этого ваш код должен быть просто:
include_once $this->views_path . $class . '.php';
Если вам нужно несколько путей «просмотреть», создайте функцию, которая загружает представления:
public function load_view($class) { // perhaps there's a mapping here instead.... foreach ($this->views_paths as $path) { $filename = $path . $class . '.php'; if (file_exists($filename)) { include_once $filename; } } throw .... }
В любом случае, в момент, когда происходит включение, у вас есть самая большая / самая точная информация о классе, который вы хотите загрузить. Использование этой информации для полной загрузки класса является единственной эффективной стратегией загрузки классов. Да, вы можете получить больше переменных класса или (не дай бог) некоторых глобальных переменных. Но это лучший компромисс, а не просто ленивый и сканирующий части файловой системы для вашего класса.