Пострадает ли производительность при использовании автоматической загрузки в php и поиске файла класса?
Я всегда боролся с тем, как лучше всего включить классы в мой php-код. Обычно это проблема, но несколько минут назад я нашел этот вопрос, который значительно помогает в этом. Теперь я читаю о __ автозагрузке и думаю, что это может значительно упростить процесс разработки моих приложений. Проблема в том, что мне нравится поддерживать структуру папок для разделения областей функциональности, а не бросать все в общую папку/lib. Поэтому, если я переопределю автоматическую загрузку на выполните глубокий поиск в папке класса, включая все вложенные папки, какие показатели производительности я могу ожидать?
Очевидно, что это будет зависеть от масштаба, глубины структуры папок и количества классов, но в целом я спрашиваю о проекте среднего масштаба, вызовет ли это проблемы.
7 answers
__автоматическая загрузка - это здорово, но стоимость указания всех файлов в функции рекурсивного поиска стоит дорого. Возможно, вам захочется взглянуть на построение дерева файлов для автоматической загрузки. В моей структуре я последовательно называю файлы для их классов и использую карту, которая кэшируется для данных.
Выезд http://trac.framewerk.org/cgi-bin/trac.fcgi/browser/trunk/index.php [ мертвая ссылка] начиная со строки 68, чтобы получить представление о том, как это может быть сделано.
Редактировать: И чтобы более прямо ответить на ваш вопрос, без кэширования вы можете ожидать снижения производительности на сайте со средним и интенсивным трафиком.
Общий шаблон (Pear, Zend Framework в качестве примеров...) состоит в том, чтобы имя класса отражало путь, поэтому Db_Adapter_Mysql будет находиться в /Db/Adapter/Mysql.php, откуда-то, что добавлено в путь включения.
Есть 2 способа, которыми вы могли бы легко это сделать, прежде всего, назовите свои классы так, чтобы они определяли структуру того, где их найти
function __autoload($classname)
{
try
{
if (class_exists($classname, false) OR interface_exists($classname, false))
{
return;
}
$class = split('_', strtolower(strval($classname)));
if (array_shift($class) != 'majyk')
{
throw new Exception('Autoloader tried to load a class that does not belong to us ( ' . $classname . ' )');
}
switch (count($class))
{
case 1: // Core Class - matches Majyk_Foo - include /core/class_foo.php
$file = MAJYK_DIR . 'core/class_' . $class[0] . '.php';
break;
case 2: // Subclass - matches Majyk_Foo_Bar - includes /foo/class_bar.php
$file = MAJYK_DIR . $class[0] . '/class_' . $class[1] . '.php';
break;
default:
throw new Exception('Unknown Class Name ( ' . $classname .' )');
return false;
}
if (file_exists($file))
{
require_once($file);
if (!class_exists($classname, false) AND !interface_exists($classname, false))
{
throw new Exception('Class cannot be found ( ' . $classname . ' )');
}
}
else
{
throw new Exception('Class File Cannot be found ( ' . str_replace(MAJYK_DIR, '', $file) . ' )');
}
}
catch (Exception $e)
{
// spl_autoload($classname);
echo $e->getMessage();
}
}
Или, 2, используйте несколько загрузчиков. PHP>=5.1.2 Имеет библиотеку SPL, которая позволяет добавлять несколько загрузчиков. Вы добавляете по одному для каждого пути, и он найдет его на своем пути. Или просто добавьте их в путь включения и используйте spl_autoload() по умолчанию
Пример
function autoload_foo($classname)
{
require_once('foo/' . $classname . '.php');
}
function autoload_bar($classname)
{
require_once('bar/' . $classname . '.php');
}
spl_autoload_register('autoload_foo');
spl_autoload_register('autoload_bar');
spl_autoload_register('spl_autoload'); // Default SPL Autoloader
Автозапуск - отличная функция PHP, которая вам очень поможет... Производительность не пострадала бы, если бы мы использовали интеллектуальную таксономию, такую как: 1. каждая библиотека остается в папках "пакеты". 2. каждый класс находится путем замены "_" в имени класса на "/" и добавления ".php" в конце файла class = My_App_Smart_Object = packages/My/App/Smart/Object.php
Преимущества этого подхода (используемого практически любым фреймворком) также заключаются в более разумной организации вашего кода:-)
Поиск файлов повсюду замедлит работу (намного больше попаданий на диск). Загрузка всех ваших классов на случай, если они вам понадобятся, потребует больше памяти. Указание того, какие классы вам нужны в каждом файле, трудно поддерживать (т. Е. Они не удаляются, если они больше не используются).
Реальный вопрос в том, что из этого для вас важнее? В конце концов, все это компромиссы, так что вам придется выбрать один. Однако можно утверждать, что большая часть накладных расходов во втором и третьем вариантах речь идет о фактической компиляции кода. Использование чего-то вроде APC может значительно снизить накладные расходы на загрузку и компиляцию каждого класса при каждой загрузке страницы.
Учитывая использование APC, я бы, скорее всего, разделил свой код на модули (например, модуль веб-интерфейса, модуль взаимодействия с базой данных и т.д.) и попросил бы каждый из этих модулей импортировать все классы для своего модуля, а также классы из других модулей, которые им могут понадобиться. Это компромисс между двумя последними, и я обнаружил, что он работает достаточно хорошо для моих нужд.
Я склонен использовать простой подход, при котором __autoload() консультируется с именами классов сопоставления хэша с относительными путями, которые содержатся в файле, который восстанавливается с помощью простого скрипта, который сам выполняет рекурсивный поиск.
Для этого требуется, чтобы скрипт запускался при добавлении нового файла класса или реструктуризации базы кода, но он также позволяет избежать "хитрости" в __autoload(), которая может привести к ненужным вызовам stat(), и это имеет то преимущество, что я могу легко перемещать файлы в рамках моей базы кода, зная, что все, что мне нужно сделать, это запустить один скрипт для обновления автозагрузчика.
Сам скрипт рекурсивно проверяет мой каталог includes/ и предполагает, что любой PHP-файл, не указанный в коротком списке исключений (сам загрузчик плюс некоторые другие стандартные файлы, которые у меня обычно есть), содержит класс с тем же именем.
Подход Zend Framework заключается в том, чтобы выполнять автоматическую загрузку на основе стандарта папки PEAR (class_foo сопоставляется с /Class/Foo.php), однако вместо использования заданного базового пути он использует include_path.
Проблема с их подходом заключается в том, что невозможно заранее проверить, существует ли файл, поэтому автоматическая загрузка попытается включить файл, которого нет ни в одном из путей include_path, с ошибкой, и никогда не даст другим функциям автоматической загрузки, зарегистрированным в spl_autoload_register, возможность включить файл.
Таким образом, небольшое отклонение заключается в том, чтобы вручную предоставить массив базовых путей, в которых автоматическая загрузка может ожидать найти классы, настроенные в стиле PEAR, и просто выполнить цикл по базовым путям:
<?php
//...
foreach( $paths as $path )
{
if( file_exists($path . $classNameToFilePath) )
include $path . $classNameToFilePath;
}
//...
?>
Конечно, вы будете вроде как искать, но для каждой загрузки вы будете выполнять только в худшем случае n поисков, где n - количество базовых путей, которые вы проверяете.
Но если вам все еще приходится рекурсивно сканировать каталоги, вопрос не в том, "Повредит ли автоматическая загрузка моему производительность", вопрос должен звучать так: "почему я разбрасываю файлы своих классов в случайной структуре?" Придерживаясь структуры PEAR, вы избавите себя от многих головных болей, и даже если вы решите выполнить включение вручную, в отличие от автоматической загрузки, не будет никаких догадок о том, где находятся файлы классов, когда вы выполняете инструкции include.