Отвечу как пользователь фреймворка Kohana (с той самой КФС).
В проекте имеются условные папки Application, System и Modules (естественно, названия могут быть любыми). В System хранится код ядра фреймворка (базовые классы для роутинга, MVC/HMVC, хэлперы и т.д.). В Modules — куча подключаемых модулей, как стандартные (Database, ORM, Cache и т.д.), так и собственные разработки. Ну и в Application остается код, специфичный для данного приложения (т.е. который Вы не планируете переносить на другие приложения).
Любой используемый модуль должен быть явно объявлен в системе (
Kohana::modules($module_list)
). При добавлении модуля (или списка модулей) происходит следующий алгоритм:
0. В главном классе модуля есть статическая переменная $_paths, в которой хранятся все пути КФС. Изначально в него добавляется путь к Application.
1. Проверяется путь к модулю, если нет — модуль игнорируется.
2. Модуль добавляется в $_path. Делается проверка на существование файла init.php в корне модуля. Если он есть, то выполняется. Таким образом, можно осуществлять какие-то стартовые действия (загрузка конфигов, добавление роутинга и т.д.).
3. Последним в список добавляется System.
Структура файлов и папок одинаковая, что в Application, что в System, что в каждом модуле. После выстраивания списка путей в ряд мы получаем возможность проходиться по нему в поиске нужного класса. Например, если есть модули A, B, C, а в B и C имеется класс Foo, то система выберет класс из модуля B, так как он идет раньше в списке путей. На очередность влияет порядок упоминания классов в списке вызова
Kohana::modules()
. Пути при каждом запуске генерируются заново, но вот результаты поиска файлов кэшируются, чтобы меньше шуршать по винту.
Для понимания такой структуры очень полезно посмотреть на
эту картинку. В результате часто собственно проект (Application) состоит из конфигов и файла запуска (bootstrap), все остальное выносится в модули.
Кроме того, гибкость и расширяемость фреймворка достигается засчет «пустых» классов, например есть Database и Kohana_Database (extends Database). Весь изначальный функционал реализован в Kohana_Database, но в коде мы используем Database. Соответственно можно где-то в Application или в одном из модулей добавить свой класс Database (в таком случае система загрузит его, а не аналог из System), и в нем сделать нужные изменения.
PS. А эвенты все равно удобная штука (хоть и достаточно простые —
Event::add()
и
Event::run()
). Их в Kohana v3 штатно уже нет (т.к. имеется достаточный контроль над выполнением Request'а), поэтому приходится вручную прикручивать для собственных событий.