Недавно я начал разрабатывать очередной php проект, который использует множество классов, так как полностью построен на ООП. Следовательно я решил использовать автозагрузчик классов, однако мне нужен был такой, который мог бы найти любой класс в проекте, и при этом не слишком нагружал систему. Был написан следующий код:
Надеюсь кому-нибудь пригодится данный код в его работе.
<?php
class autoload {
//Список директорий, которые следует исключить из поиска
private static $exception_list = [];
//Список ранее найденных директорий
private static $founded_list = [];
public static function search($dir, $file_to_search) {
//Если попали на директорию, исключенную из поиска, или уже подключали требуемый класс то игнорируем ее
if(in_array($dir, static::$exception_list) || isset(static::$founded_list[$file_to_search])) {
return;
}
//Сканируем текущую директорию в поисках класса
$scan = glob("$dir/*");
foreach ($scan as $path) {
if (preg_match('/\.php$/', $path) && is_file($path)) {
//Если нашли, то "запоминаем" директорию и подключаем файл
static::$founded_list[basename($path)] = $path;
if(basename($path) == $file_to_search) {
include_once $path;
return;
}
}
elseif (is_dir($path)) {
self::search($path, $file_to_search);
}
}
}
}
function __autoload(string $class){
Autoload::search(ROOT, $class . '.php');
}
Надеюсь кому-нибудь пригодится данный код в его работе.
Комментарии (17)
FanatPHP
17.09.2018 11:52+3Я правильно понимаю, что эта штука заново сканирует директории для каждого загружаемого класса? И это называется "быстрая загрузка"?
И неймспейсы, как я понимаю, в проекте не используются?
peresada
17.09.2018 12:07Заминусуют еще сильнее, даже если бы код был идеальным и работал бы он быстрее стандартных автозагрузчиков, все равно простая публикация кода на хабре не приветствуется — используйте для этого gist в github'е
Raserad Автор
17.09.2018 12:37Хорошо, все понятно)) Для этого я и опубликовал здесь данный код, чтобы мне указали на ошибки. Этого я и хотел — критики)) Так что всем спасибо.))))
NorthDakota
Бегите…
Просто оставлю эти слова здесь
2018, composer, deprecated, psr-0, psr-1, psr-2, psr-4
Raserad Автор
Хорошо, пожалуйста, перечислите здесь нарушения данных стандартов, чтобы я знал как писать код в будущем, и чтобы другие тоже видели.
А так же насчет composer. Я понимаю, что его использует сейчас огромное количество современных проектов, однако, как ни странно, он не на всех серверах есть, и мне кажется что гораздо проще написать один маленький класс, который автоматически будет находить нужные классы и подгружать их, чем тащить composer. Но все зависит от конкретных требований проекта))
NorthDakota
Хорошо. немного конструктива
1. Магический метод __autoload уже давно никто не использует, так же он обьявлен deprecated начиная с версии 7.2
Вместо этого используйте spl_autoload_register
2. Статика, старайтесь избегать использование статики, ибо она оправдана в очень редких и специфичных местах, если же вы хотели добится чего то типа «кеша» то нужно курить в сторону Singleton
3. Излишние коментарии. Вместо того чтобы комментировать каждую строчку комментарием «это код», «это переменная», постарайтесь придумать название для переменной/метода чтобы название говорило всё о нём.
Например exception_list — во первых list явно лишнее, так как видно что это массив, приходим логически к exceptions — сбивает с толку, кажется что это будет массив пхп исключений. Заменим на excluded, уже более нормально но нужно добавить ещё что именно excluded.
excludedFolders, excluededDirs — уже более подходящие названия
4. По качеству кода ещё очень много мелких замечаний, лутше перейду к psr'ам
psr-0, psr-4 собственно описывают как написать autoload, обязательно к прочтению
psr-1, psr-2 стиль кода собственно, старайтесь использовать camelCase и тд (то что укололо глаз)
Ну и напоследок, если взялись что то делать, проверьте, поищите как это сделано было уже до вас. Например glob и рекурсивность можно с легкостью заменить использованием RecursiveDirectoryIterator. Придумывать свой велосипед это весело и полезно, но юзать в продакшене очень рисковано
NorthDakota
А ну и про композер забыл,
Его не дураки писали, и я на 99% уверен что его автозагрузка будет на 99% быстрее и «рекурсивней» вашего подхода,
По поводу того что его нету на всех серверах. Композер — это пхп апликейшн, и поставить его даже не имея рут прав раз плюнуть
PS. Только заметил что ваш скрипт загружает все файлы, даже если они не используются в текущем реквесте, так что ваш автозагрузчик очеееень медленный
m03r
Да вроде бы нет — include происходит только при совпадении basename.
NorthDakota
Я немного о другом. Если в проекте 100500 файлов, а при реквесте на один контроллер реально будет использоваться только 10 классов, то в память будут загружены все 100500 вместо 10. Но фиг с ней с памятью, а вот диск при чтении этих 100500 файлов немножко будет напрягаться.
Также благодаря этому basename если у нас будет несколько класов с одинаковыми названиеми но разными неймспейсами то последний не будет загружён
m03r
Да вроде бы не будет — каждый раз читаются только оглавления директорий (впрочем, смотрю код с телефона и могу чего-то не заметить). А вот с одинаковыми названиями возможны хитрые глюки, когда в разных средах порядок перечисления будет разный.
m03r
По PSR-4 классы раскладываются по директориям в соответствии со своими неймспейсами. Поэтому вычисление имени файла и пути к нему по классу производится простой заменой. А у вас каждый раз при поиске файла происходит glob по всем директориям, что может быть весьма небыстро. Кроме этого, держать в памяти список найденных файлов бессмысленно: автозагрузка работает один раз для каждого класса.
В вашем случае (как я понимаю, просто классы по файлам в разных директориях) эффективнее всего просто заранее проходить по всем файлам и составлять кеш соответствий в виде статического массива в данном классе: он ещё и ляжет в опкеш и не будет перечитываться с диска каждый раз. Композер, собственно, ровно так и делает в одном из вариантов.
И да, код оформлен не по PSR-2.
PaulZi
в чём сложности с установкой composer?
m03r
Я бы не стал ставить composer только для автозагрузки. Всё-таки в первую очередь это менеджер пакетов, а автозагрузка пользовательских классов — так, приятный бонус.
PaulZi
А что вас пугает? Используйте только `composer dumpautoload`, это лучше чем такие лесопеды писать.
m03r
Тянуть большие зависимости ради маленького кусочка функционала редко оправданно, и для этого всегда нужны серьёзные обоснования. А лесапед для PSR-4 пишется в несколько строк, и его сложно написать плохо.
dumistoklus
Если composer нет на сервере, значит можно установить локально и залить проект на сервер вместе с папкой vendor, где и лежит загрузчик классов.
К тому же в композере есть дев режим, а есть режим сборки. В дев режиме, классы подгружаются динамически по мере надобности проверяя наличие файла при каждом вызове. В режиме сборки, собираются данные о всех классах, и создается файл с этими данными. При надобности, файл с классом подгружается, если он есть в списке. А благодаря дисковым кешам, это может проходить моментально. Никаких сканирований директорий, в момент вызова скрипта не происходит, что позволяет ускорить приложение.