Модульная архитектура на примерах..?
Я делал свой фреймверк на основе евентов. В ядре при каждом чихе генерится евент, дополнения этим пользуются, при желании генерят свои. Удобно, не накладно, быстро и просто. Недостаток — при евенте видна лишь та часть приложения которую тебе дали.
При использоании каскадной файловой системы тоже есть свои преимущества, но это медленней, как ни крути а скан фс и поиск файлов это долго.
Еще есть варианты с регистрацией компонентов в ядре и потом ядровызывает их само, но я с такими вещами не работал, мне кажется это не акруально.
Отвечу как пользователь фреймворка 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'а), поэтому приходится вручную прикручивать для собственных событий.