Повлияет ли производительность при использовании автозагрузки в php и поиске файла класса?
Я всегда боролся с тем, как лучше всего включить классы в мой php-код. Путь обычно является проблемой, но несколько минут назад я нашел этот вопрос, который значительно помогает этому. Сейчас я читаю о __autoload и думаю, что это может значительно облегчить процесс разработки моих приложений. Проблема в том, что мне нравится поддерживать структуру папок в отдельных областях функциональности, а не бросать все в общую папку / lib. Так что, если я переопределю автозагрузку для глубокого поиска в папке классов, включая все подпапки, каких результатов я могу ожидать?
Очевидно, что это будет зависеть от масштаба, глубины структуры папок и количества классов, но, как правило, я спрашиваю, что для проекта среднего масштаба это вызовет проблемы.
7 ответов
__autoload - это здорово, но стоимость указания всех файлов в функции рекурсивного поиска обходится дорого. Возможно, вы захотите взглянуть на создание дерева файлов для использования для автозагрузки. В моей структуре я последовательно называю файлы для их классов и использую карту, которая кэшируется для данных.
Проверьте http://trac.framewerk.org/cgi-bin/trac.fcgi/browser/trunk/index.php [мертвая ссылка], начиная со строки 68, чтобы понять, как это можно сделать.
Изменить: и чтобы более прямо ответить на ваш вопрос, без кеширования, вы можете ожидать снижения производительности на сайте со средним и большим трафиком.
Распространенный шаблон (Pear, Zend Framework в качестве примеров...) заключается в том, чтобы имя класса отражало путь, поэтому Db_Adapter_Mysql будет находиться в /Db/Adapter/Mysql.php, откуда-то, что добавлено в include-путь.
Есть два способа, которыми вы можете легко сделать это, во-первых, назвать ваши классы так, чтобы они определяли структуру, где их искать
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 file = packages/My/App/Smart/Object.php
Преимущества этого подхода (используемого практически в любой среде) также являются более разумной организацией вашего кода:-)
Я склонен использовать простой подход, где __autoload() обращается к именам классов хеш-сопоставления с относительными путями, которые содержатся в файле, который регенерируется с использованием простого сценария, который сам выполняет рекурсивный поиск.
Это требует, чтобы скрипт запускался при добавлении нового файла класса или реструктуризации базы кода, но он также избегает "хитрости" в __autoload(), которая может привести к ненужным вызовам stat(), и имеет то преимущество, что я могу легко перемещать файлы в моей базе кода, зная, что все, что мне нужно сделать, это запустить один скрипт для обновления автозагрузчика.
Сам скрипт рекурсивно проверяет мой каталог include / и предполагает, что любой файл PHP, не указанный в кратком списке исключений (сам автозагрузчик, плюс некоторые другие стандартные файлы, которые у меня есть), содержит класс с таким же именем.
Охота на файлы повсюду замедлит работу (еще много попаданий на диск). Загрузка всех ваших классов на случай, если они вам могут понадобиться, заставит вещи занимать больше памяти. Указание, какие классы вам нужны в каждом файле, сложно поддерживать (т.е. они не удаляются, если они больше не используются).
Вопрос в том, что из этого важнее для вас? В конце концов, это все компромиссы, поэтому вы должны выбрать один. Однако можно утверждать, что большая часть накладных расходов во втором и третьем вариантах связана с фактической компиляцией кода. Использование чего-то вроде APC может значительно снизить накладные расходы при загрузке и компиляции каждого класса при каждой загрузке страницы.
Учитывая использование APC, я, вероятно, предпочел бы разделить мой код на модули (например, модуль веб-интерфейса, модуль взаимодействия с базой данных и т. Д.), И каждый из этих модулей импортировал бы все классы для своего модуля, а также классы. из других модулей они могут понадобиться. Это компромисс между двумя последними, и я обнаружил, что он работает достаточно хорошо для моих нужд.
Подход Zend Framework заключается в том, чтобы выполнять автозагрузку на основе стандарта папки PEAR (Class_Foo отображается на /Class/Foo.php), однако вместо использования заданного базового пути он использует include_path.
Проблема с их подходом заключается в том, что нет способа заранее проверить, существует ли файл, поэтому автозагрузка попытается включить файл, который не существует ни в одном из include_path, error out, и никогда не выдаст никакие другие функции автозагрузки, зарегистрированные в spl_autoload_register. шанс включить файл.
Таким образом, небольшое отклонение состоит в том, чтобы вручную предоставить массив базовых путей, где автозагрузка может ожидать, что классы будут найдены в режиме PEAR и просто зацикливаться на базовых путях:
<?php
//...
foreach( $paths as $path )
{
if( file_exists($path . $classNameToFilePath) )
include $path . $classNameToFilePath;
}
//...
?>
Конечно, вы будете искать, но для каждой автозагрузки вы будете выполнять только в худшем случае n поисков, где n - количество проверяемых базовых путей.
Но если вам все еще приходится рекурсивно сканировать каталоги, вопрос заключается не в том,"загрузит ли автозагрузка мою производительность", вопрос должен быть: "Почему я перекидываю файлы классов в случайную структуру?" Придерживаясь структуры PEAR, вы избавите себя от множества головных болей, и даже если вы решите вручную выполнить включение, а не автозагрузку, не будет никакого предположения о том, где находятся файлы классов, когда вы выполняете операторы включения.