framework.zend.com
Stable релиз 2.0 / 1.12

Автозагрузка классов в приложениях на Zend Framework

К комментариям

Содержание

Введение

Вашем вниманию предлагается статья о одном из возможных решений по автозагрузке классов в приложениях использующих zend framework (далее ZF). Но так же она будет полезна, если вы используете похожие с ZF соглашения по именованию классов. Статья расчитана на средний и выше уровень знания zend framework.

Автору всегда нравилось в PHP5 возможность автозагрузки классов, поэтому в своих приложениях обычно использует эту возможность.

Автозагрузка классов ZF

Давайте взглянем, что ZF предлагает по данному поводу.
Сначала заглянем в стандарты кодирования, B.3. Соглашения по именованию:

Zend Framework использует схему именования классов, в соответствии с которой имена классов напрямую указывают на директории, где они находятся. Корневой директорией Zend Framework’а является директория "Zend/", в которой иерархически расположены все классы.
Имена классов могут содержать только буквенно-числовые символы. Числа допустимы в именах классов, но не приветствуются. Символы нижнего подчеркивания допустимы в местах разделителей пути — имя файла "Zend/Db/Table.php" должно указывать на класс с именем "Zend_Db_Table".

Автору нравиться это соглашение и он старается использовать его в своих приложениях (само соглашение не ново :). Приходится привыкать к длинным названиям классов. Используя такое соглашение проще искать классы и следить за их пространством имен (неповторимости имени класса).

Теперь взглянем, что предлагает ZF по загрузке файлов Глава 26. Zend_Loader:

Класс Zend_Loader включает в себя методы, помогающие производить динамическую загрузку файлов.

26.1.2. Загрузка классов:

Zend_Loader::loadClass('Container_Tree');
Строка, задающая класс, преобразуется в относительный путь посредством замены знаков подчеркивания разделителями директорий и добавления расширения ‘.php’ в конец. В примере выше ‘Container_Tree‘ преобразуется в ‘Container/Tree.php’.

26.1.4. Использование автозагрузчика:

После регистрации метода обратного вызова автозагрузки вы можете ссылаться на классы из Zend Framework без их явной загрузки. Метод autoload() автоматически запускает метод Zend_Loader::loadClass(), когда вы ссылаетесь на класс.

При этом сам фреймворк должен лежать в одной из папок указанных в include_path. Разработчики ZF оставляют право выбора, использовать автозагрузчик классов или нет, поэтому в самой библиотеке используется явно require_once. Если с автозагрузкой классов из ZF все в принципе понятно, включаем описанный автозагрузчик и добавляем путь к ZF в include_path, то со своими классами дело обстоит немного интереснее.

Структура проекта на ZF и автозагрузка собственных классов

Что нам предлагают? 8.11. Использование определенной соглашением модульной структуры директорий:

Определенная соглашением модульная структура директорий позволяет разделять различные приложения MVC в автономные единицы и повторно использовать их с различными фронт-контроллерами.

В общем модули — это хорошо, распылятся на эту тему не стоит :) Выделим кусок структуры, что касается модуля:


core/
controllers/
IndexController.php
FooController.php
models/
SubBar
Foo.php
Bar.php
views/
scripts/
index/
foo/
helpers/
filters/

Вот и подвох, а касается он того, что в модуле появились много папок, где будут находятся наши классы:


core/controllers
core/models
core/views/helpers

На счет контроллеров позаботился ZF, следуем рекомендациям:


<?php
$front->setControllerDirectory(array(
'default' => '/path/to/application/controllers',
'blog' => '/path/to/application/blog/controllers'
));


или


<?php
/**
* Предполагается следующая структура директорий:
* application/
* modules/
* default/
* controllers/
* foo/
* controllers/
* bar/
* controllers/
*/
$front->addModuleDirectory('/path/to/application/modules');

На счет "вьюверных хелперов" ZF тоже позаботился, добавив плагин-загрузчик 26.2. Loading Plugins


$loader = new Zend_Loader_PluginLoader(array(
'Zend_View_Helper' => 'Zend/View/Helper/',
'Foo_View_Helper' => 'application/modules/foo/views/helpers',
'Bar_View_Helper' => 'application/modules/bar/views/helpers'
));

То что приходится работать с разными загрузчиками классов — это автору не понравилось.

Модели остаются на нашей совести. Хочется, чтоб классы моделей Core_Bar и Core_SubBar_Foo находились в core/models/Bar.php и core/models/SubBar/Foo.php сответсвенно, но тут автолоадер из ZF ничего поделать не может. Вот тут и началось раздолье, что же делать с моделями, как сделать так, чтобы автозагрузчик в приложении был одним единственным, а еще лучше чтоб загружал он все по одному принципу. Автор сделал много проб, например был такой вариант вариант:


ModuleName/
_configs/
_controllers/
_views/
MainClass/
SubClassName.php
ClassName.php
...

Автолоадер остается из ZF, в include_path добавляется директория с модулями. Но эта структура не понравилась, может подчеркиванием, может заглавной буквой имени модуля(в этом случае приходилось переопределять лишние вещи в фронт-контроллере из ZF), а может еще чем…

Из вышеупомянутого плагина-загрузчика понравилась идея: определенному префиксу соответствует определенная директория. А почему бы эту идею не использовать для приложения в целом?

Итого:


Zend -> 'path/to/library/Zend'
Core -> 'path/to/module/core/models'
Core -> 'path/to/module/core/controllers'
...

Тогда если класс Zend_Controller_Front, то наш автозагрузчик найдет префикс Zend, дальше от класса останется Controller_Front, который преобразуется в Controller/Front.php(по принципу Zend_Loader), аналогично и для наших моделей: по Core_SubBar_Foo находит префикс Core, далее остается SubBar_Foo, который преобразуется SubBar/Foo.php. В результате получили отличный механизм для автозагрузки как классов из ZF, так и классов из модулей. Сам механизм очень простой, но достаточно гибкий, те же вьювер-хелперы и контроллеры хорошо вписываются в эту структуру и не только.

Остается подумать, как сделать так, чтоб не регистрировать все существующие префиксы. Не забываем про упомянутое выше соглашение по именованию классов из стандартов кодирования ZF. Тогда задача очень легко решается: регистрировать нужно папки с наборами классов, а потом эти папки просматривать и в соответствии с содержимым регистрировать префиксы. Папок с классами в хорошо продуманной файловой структуре проекта не так уж много, или описываются довольно простыми правилами. Например: регистрируем папку с библиотеками path/to/library, по содержимому ее найдется папка Zend и остальные библиотеки.

Подумаем о модулях. Модули могут постоянно добавляться, но разница добавленных папок с классами будет в названии самого модуля, если предположить, что у модулей одинаковая файловая структура(а оно так и должно быть, по идее). Приходит на ум добавить папку с модулями, а при нахождении модуля добавлять необходимый суффикс. Например: из выше приведенной структуры модуля;


Loader->addDir('path/to/modules', 'suffix/to/models');
Loader->addDir('path/to/modules', 'suffix/to/views/helpers');
...

Заключение

После того как идея есть, дело остается за малым — реализовать :)

Пример загрузчика

Оригинал статьи

P.S. Автор знаком с ZF начиная 0.1.x версий. Первое знакомство: PHPIns!de #18, Июль‘2006.

P.P.S. Еще один вариант решениея подобной проблемы.

Обсуждение на форуме

Лучший способ следить за обновлениями сайта это подписаться на RSS
Если информация была полезной для вас, вы можете поддержать сайт.
Комментарии:
Женька 27.08.2009 17:56 #
да блин. Вообще это косяк со стороны разработчиков. Могли бы так же и о модели позаботится, хоть через тот же Zend_Db.
А то надо либо расширять их автолоадер, либо setFallbackAutoloader(true) и папку с моделями в include_path.
Спрашивается, чего ради?
Ответить
Уважаемые пользователи. Комментарии не для того чтобы:
  1. Спрашивать почему у вас не работает код, для этого есть тема форума закрепленная за статьей.
  2. Спрашивать как реализовать ту или иную функциональность, для этого необходимо создать свою тему на форуме.

Комментарии для того чтобы: высказать свое аргументированное мнение о статье, указать какие участки вызывают непонимание, что нужно исправить/улучшить, просто сказать спасибо.

Комментарии имеют древовидную структуру.
Если вы хотите ответить на определенный комментарий - нажмите на ссылку "Ответить" возле этого комментария.

Комментарии не соответствующие этим правилам могут быть удалены. Спасибо за понимание.
Комментарии временно отключены, вы можете воспользоваться форумом.