Из всего волшебства в PHP мне, вероятно, больше всего нравится хук __autoload (). Это экономит много утомительных вызовов включения сценариев и может значительно ускорить ваше приложение, избавляя анализатор от ненужной работы. Несмотря на то, что он существует с момента выхода PHP5, я не нашел ни одного убедительного приложения для него. Большинство из них следуют той же схеме: всякий раз, когда создается экземпляр неопределенного класса, маленькая функция __autoload () пытается включить файл PHP, который должен быть назван в честь своего класса:
function __autoload($name) {
require_once('classes/'.$name.'.php');
}
Однако это решение негибко и имеет некоторые недостатки. Наиболее очевидным является имя класса -> ограничение имени файла. Кроме того, это означает, что все файлы классов должны храниться в одной папке. Это не вариант для проектов с несколькими классами hundert, естественно упорядоченными в каталогах пакетов. В целом, эти реализации кажутся не совсем зрелыми, а скорее доказательством концепции __autoload (). Это требует лучшего решения.
Загрузка шустро
Что, если бы у нас был маленький «искатель классов», который рекурсивно искал в каталогах PHP-скрипты и анализировал каждый из них на предмет определения классов? Во-первых, он будет знать обо всех классах в этих папках и сообщать нам, в каком файле их искать. Мы могли бы объединить это с __autoload (), чтобы помочь ему найти любой необходимый класс сам по себе. «Это глупо, это привело бы к большим накладным расходам», — скажете вы. Правильно! Так что, если мы будем кэшировать результаты после каждого поиска, зная, что файловая структура редко изменяется, если разработчик не работает над этим? Конечно, я говорю о лучшем способе кеширования, таким образом генерируя список классов в виде PHP-кода и сохраняя его для дальнейшего использования.
Сказано — сделано. Я написал класс, который реализует эту идею и претенциозно назвал его «SmartLoader», так как он достаточно умен, чтобы найти любой класс вашего PHP-приложения без посторонней помощи. Вы можете скачать его здесь под лицензией Lesser General Public License . Теперь давайте подробнее рассмотрим, как это работает:
За кулисами
Шаг 1: SmartLoader рекурсивно ищет PHP-скрипты и анализирует их на наличие классов со следующим регулярным выражением:
(interface|class)s+(w+)s+(extendss+(w+)s+)?(implementss+w+s*(,s*w+s*)*)?{
Шаг 2: Теперь у нас есть список всех доступных классов и где их найти. Этот список будет преобразован в код PHP и записан в файл кэша. Его содержимое будет выглядеть примерно так:
// this is a automatically generated cache file.
$GLOBALS['smartloader_classes']['Main'] = 'classes/main.class.php';
$GLOBALS['smartloader_classes']['Iterable'] = 'classes/containers/iterable.class.php';
$GLOBALS['smartloader_classes']['ActiveRecord'] = 'classes/database/activerecord.class.php';
/* etc. */
Шаг 3: Всякий раз, когда необходимо загрузить класс, SmartLoader проверяет кэш на его имя и включает соответствующий файл PHP. В случае, если класс не может быть найден или загружен, кэш воссоздается, и будет предпринята другая попытка включения.
Готовиться
smartloader.class.php содержит функцию автозагрузки, а также сам класс SmartLoader. Единственное, что нужно сделать, это настроить метод автозагрузки:
function __autoload($class_name) {
/* using a static loader object rather than a singleton to reduce overhead */
static $ldr = null;
/* initializing loader */
if(!$ldr) {
$ldr = new SmartLoader();
}
/* defining cache file, make sure write permissions */
$ldr->setCacheFilename('cache/smartloader_cache.php');
/* adding directories to parse. better use absolute paths. */
$ldr->addDir("classes");
/* what are the endings of your class files? */
$ldr->setClassFileEndings(array('.php', '.class'));
/* should SmartLoader follow symbolic links? */
$ldr->setfollowSymlinks(false);
/* it should probably ignore hidden dirs/files */
$ldr->setIgnoreHiddenFiles(true);
}
/* load the class or trigger some fatal error on failure */
if(!$ldr->loadClass($class_name)) {
trigger_error("Cannot load class '".$class_name."'", E_USER_ERROR);
}
}
После этого вам просто нужно включить smartloader.class.php в ваши скрипты и больше не беспокоиться о включении классов.
преимущества
- Удобство: SmartLoader упрощает управление файлами классов. Вы можете переименовать их, переместить их или реорганизовать их в (пакет) папки. Пока они находятся в вашем веб-пространстве, SmartLoader может их найти.
- Скорость: с SmartLoader файлы классов загружаются только тогда, когда они действительно необходимы. Такой подход, называемый «отложенной загрузкой» или «как раз вовремя» (не путать с интерактивным программированием), может сэкономить PHP много разборов и компиляции, вызванных избыточными включениями.
- Портативность, обратная совместимость: вы можете легко использовать SmartLoader, не нарушая существующие приложения. __autoload () включается только тогда, когда по умолчанию создается экземпляр несуществующего класса.
Потенциальные ловушки
- Обработка ошибок: вы можете использовать любой вариант обработки ошибок, который вам нравится. Ну, почти: исключения не могут быть вызваны через __autoload (). Помните, что это особенность, а не ошибка . Это возможно, хотя и со страшным взломом eval (), но я не буду вдаваться в подробности.
- Системы контроля версий: если ваше веб-пространство является рабочей копией какой-либо системы контроля версий, вы, вероятно, должны сказать SmartLoader игнорировать скрытые файлы. Это улучшит его производительность и предотвратит сканирование тех устаревших устаревших копий файлов, которые находятся в папках .SVN / .CVS.
- Я не должен вам этого говорить, но не позволяйте SmartLoader сканировать циклы символьных ссылок.
- Профилирование: Zend Profiler запутывается в SmartLoader и начинает вычислять недопустимые результаты для своего времени выполнения.
- Кэши опкодов: я недостаточно хорошо знаю внутреннюю работу APC, Zend Optimizer и им подобных, но могу представить, что динамические включения, используемые в SmartLoader, сводят на нет производительность, получаемую от кеширования опкодов. Я не смог проверить это, поскольку Zend Profiler отказывается правильно работать с SmartLoader (см. Выше). Я был бы рад получить любые отзывы по этому вопросу.