Модули в Yii 2: когда выносить код в модуль, а когда нет
Модуль в Yii 2 — не единственный способ разделить приложение на части. Разбираем, где модуль оправдан, а где хватит неймспейса, и чем платите за каждый вариант.

Приложение выросло: контроллеры админки лежат вперемешку с публичной частью, у API свои маршруты, а команда хочет распилить код на изолированные куски. В Yii 2 напрашивается ответ — модуль. Но у Yii есть как минимум три способа разграничить приложение, и модуль из них самый тяжёлый. Разберём, когда он оправдан, а когда добавляет структуру, за которую вы потом платите каждым обращением к чужому коду.
Статья про Yii 2.0.x (актуальная ветка на момент написания). Речь только про способы структурного разделения внутри одного приложения — межприложенческие связи и микросервисы здесь не рассматриваем.
Задача и почему «просто модуль» — не всегда ответ
Допустим, у вас интернет-магазин: витрина, личный кабинет, админка. Очевидное решение — сделать три модуля: catalog, cabinet, admin. Каждый со своим namespace, своими контроллерами и представлениями. Выглядит аккуратно.
Проблема в том, что модуль в Yii 2 — это отдельный компонент со своим жизненным циклом: он инициализируется через init(), регистрируется в конфиге, имеет собственный controllerNamespace, может иметь свои компоненты и параметры. За эту изоляцию вы платите: каждый URL внутри модуля получает префикс, роутинг усложняется, а обращение к контроллеру из другого места становится Yii::$app->getModule('admin') вместо прямого вызова. Если куску кода изоляция не нужна, модуль превращается в бюрократию.
Три подхода к разделению
1. Просто неймспейсы и подпапки контроллеров
Самый лёгкий вариант. Контроллеры лежат в подпапках controllers/admin/, представления — в views/, всё это в едином приложении без границ. Разделение чисто визуальное: файлы разложены по папкам, но с точки зрения фреймворка это одно пространство.
// app/controllers/admin/ProductController.php
namespace app\controllers\admin;
use yii\web\Controller;
class ProductController extends Controller
{
// маршрут по умолчанию: admin/product/index
public function actionIndex()
{
return $this->render('index');
}
}Что выигрываете: ноль конфигурации, файлы разложены логично. Чем платите: нет ни изоляции компонентов, ни отдельных настроек, ни возможности отключить кусок целиком. Общий controllerNamespace приложения должен видеть эти подпапки.
2. Модуль
Полноценная единица со своим неймспейсом, конфигом и точкой инициализации. Регистрируется в config/web.php:
// config/web.php
'modules' => [
'admin' => [
'class' => 'app\modules\admin\Module',
],
],// app/modules/admin/Module.php
namespace app\modules\admin;
class Module extends \yii\base\Module
{
// Yii сам подставит app\modules\admin\controllers
public function init()
{
parent::init();
// здесь можно задать свои компоненты, layout, параметры
}
}Маршрут до контроллера теперь admin/product/index — модуль добавляет свой ID первым сегментом. Внутри модуля можно задать собственный layout, свои компоненты, параметры и даже вложенные модули.
Что выигрываете: изоляцию неймспейса, отдельную конфигурацию, возможность подключать/отключать модуль целиком одной строкой конфига, переиспользуемость (модуль можно упаковать в composer-пакет). Чем платите: обязательный класс Module, регистрация в конфиге, префикс в URL (который придётся править через urlManager, если он нежелателен), и обращение к модулю через getModule().
3. Отдельное приложение (application)
Классика Yii 2 — advanced-шаблон с приложениями frontend, backend, console. У каждого свой входной скрипт, свой конфиг, свой домен или поддомен. Это не модуль внутри приложения, а несколько приложений с общим слоем common.
Что выигрываете: полную изоляцию, вплоть до разных сессий и разных доменов для админки и витрины. Чем платите: дублирование инфраструктуры — свой bootstrap, свои ассеты, свой веб-корень на каждое приложение. Это тяжелее модуля на порядок.
Сравнение
| Критерий | Подпапки | Модуль | Приложение |
|---|---|---|---|
| Изоляция namespace | частичная | полная | полная |
| Свои компоненты/конфиг | нет | да | да |
| Отдельный домен | нет | нет | да |
| Префикс в URL | нет | да, по умолчанию | зависит от домена |
| Отключить целиком | нет | строкой конфига | отдельный веб-корень |
| Стоимость входа | минимальная | средняя | высокая |
Модуль оправдан там, где кусок кода имеет собственный жизненный цикл: свои компоненты, свою инициализацию, возможность жить как отдельный пакет. Если всё, что вам нужно, — разложить контроллеры по папкам, модуль вы заводите ради одного пустого класса.
Когда что выбирать
- Подпапки — когда разделение чисто организационное: контроллеров стало много, хочется порядка, но им не нужны отдельные компоненты или конфиг. Пример: группировка публичных контроллеров по разделам сайта.
- Модуль — когда у куска своя логика инициализации, свои компоненты (например, отдельный форматтер или свой набор параметров), или его планируют переиспользовать в другом проекте. Пример: модуль оплаты, который вы ставите как composer-пакет в несколько проектов.
- Приложение — когда админка и витрина должны быть физически разделены: разные домены, разные сессии, разный уровень доступа на уровне веб-сервера. Пример: backend на поддомене admin. с отдельной аутентификацией.
Что ломается на практике
Три типичные ошибки при работе с модулями Yii 2:
- Забытая регистрация в конфиге. Класс
Moduleсоздан, контроллеры на месте, но модуль не прописан вmodules— и вы получаетеNot Found (#404)на любой его маршрут. Фреймворк просто не знает про модуль. - Обращение к контроллеру модуля напрямую. Попытка вызвать контроллер модуля так, будто он в основном приложении, даёт ошибку разрешения маршрута. Внутри модуля маршруты относительные, извне — через ID модуля первым сегментом.
- Нежелательный префикс в URL. Клиент не хочет видеть
/admin/или/catalog/в адресе. Это правится правилами вurlManager, но про это забывают и потом переписывают половину ссылок. Планируйте роутинг до того, как заведёте модуль.
Ещё один момент: у модуля есть свой init(), и соблазн навесить туда бизнес-логику велик. init() вызывается при первом обращении к модулю через getModule() — не делайте там тяжёлых операций, это ударит по времени ответа на каждом запросе к модулю.
Что делать дальше
Начните с самого лёгкого варианта, который решает задачу, и повышайте уровень только когда упрётесь. Разложили контроллеры по папкам — работает и хватает? Не заводите модуль. Понадобились свои компоненты или переиспользование — переходите на модуль. Потребовалась изоляция на уровне домена и сессий — только тогда advanced-шаблон с приложениями.
Перед тем как завести модуль, проверьте раздел про Modules и про Applications в официальном руководстве Yii 2 — там описан жизненный цикл и порядок инициализации, от которого зависит поведение под нагрузкой. И заранее продумайте роутинг: префиксы модулей проще заложить в urlManager, чем вычищать из готовых ссылок.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: Yii 2 Guide — Modules, Yii 2 Guide — Applications
Частые вопросы
У меня Yii 2.0.15, а не последняя версия — подходы отличаются?
Можно ли вложить модуль в модуль?
Не работает маршрут модуля — выдаёт 404, что проверить первым?
Как убрать префикс модуля из URL?
Стоит ли выносить весь код в модули по умолчанию?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.