Что такое Yii
Yii — full-stack PHP-фреймворк с сильным уклоном в быстрые CRUD-приложения, админки, кабинеты, каталоги, формы и REST API. В классическом Yii-проекте из коробки есть MVC-структура, routing, controllers, views, models, validation, Active Record, migrations, widgets, RBAC, debug toolbar, консольный скрипт yii и генератор кода Gii.
В этой статье речь в основном о Yii 2, потому что именно он чаще встречается в существующих full-stack проектах с Gii, ActiveRecord-моделями, GridView и типовыми админками. Если Laravel часто продаёт «единый framework-way», а Symfony — компонентность и явные границы, Yii занимает более прагматичную нишу: быстро поднять приложение вокруг базы данных, форм и административного интерфейса.
Yii ставится через Composer, Packagist и composer.json, использует namespaces и autoloading, поэтому хорошо ложится на темы Неймспейсы и use и Autoloading и PSR-4. Но его стиль заметно отличается от PSR-first microframework-подхода из Slim и Mezzio: Yii даёт готовую application structure и много собственных abstractions.
MVC и request lifecycle
Типовой Yii 2 basic project имеет знакомую структуру: config/, controllers/, models/, views/, runtime/, vendor/, web/, yii. Веб-доступным должен быть только каталог web/; входная точка — web/index.php. Остальной PHP-код находится вне document root, что важно для безопасности и деплоя.
project/
├── config/ # конфигурация приложения и компонентов
├── controllers/ # controller classes и actions
├── models/ # Active Record и form models
├── views/ # PHP-шаблоны views
├── runtime/ # cache, logs, временные файлы
├── vendor/ # Composer-зависимости
├── web/ # document root: index.php, assets
└── yii # консольный entry scriptYii реализует MVC: controller принимает route, получает данные из request, вызывает model, затем рендерит view и возвращает response. Это та же предметная область, что в SAPI и суперглобалы, GET, POST и фильтрация ввода и HTTP-заголовки, ответы и редиректы, только завернутая в framework components.
flowchart TD
A[HTTP request] --> B[web/index.php]
B --> C[Yii application]
C --> D[Request component resolves route]
D --> E[Controller]
E --> F[Action filters]
F --> G[Action executes]
G --> H[Model / Active Record]
G --> I[View / widget rendering]
I --> J[Response component]
H --> I
J --> K[HTTP response]Минимальный controller action выглядит так:
namespace app\controllers;
use yii\web\Controller;
use yii\web\Response;
final class HealthController extends Controller
{
public function actionIndex(): array
{
\Yii::$app->response->format = Response::FORMAT_JSON;
return ['ok' => true];
}
}По умолчанию route в Yii часто следует схеме controller/action: например, health/index. Можно настраивать pretty URLs, rules и REST-контроллеры, но базовая mental model остаётся простой: route выбирает controller action, action готовит данные, view или response отправляет результат.
Active Record и работа с базой
Одна из центральных частей Yii — yii\db\ActiveRecord. Active Record class связан с таблицей, объект — со строкой, attribute — с колонкой. Поэтому Yii особенно удобен, когда приложение естественно растёт вокруг реляционной базы: пользователи, заказы, товары, статусы, справочники, права доступа.
namespace app\models;
use yii\db\ActiveRecord;
final class Product extends ActiveRecord
{
public static function tableName(): string
{
return '{{%product}}';
}
public function rules(): array
{
return [
[['title', 'price'], 'required'],
['title', 'string', 'max' => 255],
['price', 'number', 'min' => 0],
];
}
}Сохранение выглядит лаконично:
$product = new Product();
$product->title = 'Клавиатура';
$product->price = 7900;
if (!$product->save()) {
var_dump($product->getErrors());
}Важно не путать Active Record с магической защитой от всех SQL-проблем. Для обычных значений Yii строит параметризованные запросы, но архитектурные правила из PDO и подключение к базе и Prepared statements и SQL injection всё равно остаются актуальны: имена таблиц и колонок нельзя принимать из пользовательского ввода без allowlist, сложные отчёты иногда лучше писать через Query Builder или SQL, а массовые выборки стоит делать через batch(), each() или asArray(), чтобы не раздувать память объектами.
Отношения описываются методами hasOne() и hasMany():
final class Order extends ActiveRecord
{
public function getCustomer()
{
return $this->hasOne(Customer::class, ['id' => 'customer_id']);
}
}
$order = Order::find()->with('customer')->where(['id' => 10])->one();
echo $order->customer->email;Gii: генерация моделей, CRUD и админок
Gii — web-based code generator, который в dev-окружении подключается как module. Он умеет генерировать Active Record models, CRUD controllers, views, forms и search models. В типичном сценарии вы создаёте таблицу миграцией, затем через Gii получаете модель Product, ProductController, ProductSearch и views для списка, просмотра, создания и редактирования.
models/Product.php
models/ProductSearch.php
controllers/ProductController.php
views/product/index.php
views/product/view.php
views/product/create.php
views/product/update.php
views/product/_form.php
views/product/_search.phpphp yii gii/model --tableName=product --modelClass=Product
php yii gii/crud \
--modelClass="app\\models\\Product" \
--controllerClass="app\\controllers\\ProductController"Это не значит, что сгенерированный код надо оставлять как есть. Gii хорош как стартовая точка: быстро получить рабочий CRUD, затем убрать лишнее, вынести бизнес-логику из controller, настроить validation, access rules, labels, search filters и UI. Для внутренней админки это часто экономит часы. Для публичного продукта с тонкой UX-логикой Gii-код обычно становится черновиком, а не финальной архитектурой.
Forms, validation и widgets
В Yii model — это не только Active Record. Для login form, contact form, фильтров и одноразовых сценариев часто создают класс от yii\base\Model, где есть attributes и rules(), но нет таблицы в базе.
use yii\base\Model;
final class LoginForm extends Model
{
public string $username = '';
public string $password = '';
public function rules(): array
{
return [
[['username', 'password'], 'required'],
['username', 'string', 'max' => 64],
];
}
}Во view форма обычно строится через yii\widgets\ActiveForm:
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['id' => 'login-form']);
echo $form->field($model, 'username');
echo $form->field($model, 'password')->passwordInput();
echo Html::submitButton('Войти', ['class' => 'btn btn-primary']);
ActiveForm::end();ActiveForm связывает HTML-поля с model attributes и validation rules. Это удобно, но не отменяет правил из XSS, экранирование вывода и шаблоны: вывод всё равно нужно экранировать по контексту, а HTML helpers использовать осознанно.
Widgets — переиспользуемые блоки во views. В Yii это не «виджеты на дашборде», а PHP-классы, которые генерируют UI: ActiveForm, GridView, ListView, DetailView, Menu, LinkPager, Pjax-обёртки и сторонние widgets. Именно поэтому Yii хорошо подходит для админок: список с фильтрами, сортировкой и пагинацией можно собрать поверх ActiveDataProvider и GridView быстрее, чем писать весь HTML вручную.
RBAC и доступы
Для авторизации Yii предлагает access control filters и RBAC. Access Control Filter подходит для простых правил вроде «только авторизованные пользователи могут открыть /admin». RBAC нужен, когда есть роли, permissions и наследование: author может createPost, admin наследует права author и дополнительно может updatePost.
Yii поддерживает PhpManager для хранения auth data в PHP-файле и DbManager для хранения в базе. В реальных админках чаще нужен DbManager, потому что роли и назначения меняются без деплоя. При этом RBAC не должен превращаться в бизнес-логику, разбросанную по views. Проверки доступа лучше держать рядом с controller actions, policies/services или явно выделенными permission checks.
if (\Yii::$app->user->can('updateProduct', ['product' => $product])) {
// показать кнопку редактирования или выполнить действие
}Где Yii особенно уместен
Yii уместен в проектах, где база данных и CRUD — центр приложения: back-office, CRM-подобные системы, каталоги, внутренние панели, legacy-приложения, где важны понятные forms, grids, роли, миграции и быстрый scaffolding. Он также встречается в long-lived проектах, где команда уже накопила свои widgets, modules и conventions.
Главные риски Yii — переоценить Gii и недооценить архитектуру. Сгенерированный CRUD легко начинает жить как «вся система»: толстые controllers, Active Record с бизнес-логикой, view-файлы с условиями доступа, сложно тестируемые сценарии. Если проект растёт, Yii-коду нужны те же инженерные практики, что и любому PHP-приложению: ясные классы из Классы, объекты и видимость, интерфейсы там, где есть сменяемые реализации из Наследование, интерфейсы и трейты, статический анализ из PHPDoc, generics и статический анализ, тесты из PHPUnit, моки и стабы и аккуратный deploy pipeline.
Если нужен современный ecosystem-first фреймворк с большим количеством готовых продуктовых пакетов, сравните Yii с Laravel. Если важна компонентная архитектура и enterprise-инфраструктура, смотрите Symfony. Если приложение — тонкий HTTP API с несколькими middleware, Yii может быть тяжелее, чем Slim и Mezzio. А для выбора по команде, найму, legacy constraints и сроку поддержки полезна отдельная статья Выбор PHP-фреймворка.
См. также
- PDO и подключение к базе — нижний уровень, на котором строятся Yii DB connection, Query Builder и Active Record.
- Prepared statements и SQL injection — где ORM помогает, а где всё равно нужны allowlists и аккуратная сборка SQL.
- XSS, экранирование вывода и шаблоны — правила безопасного вывода во views и widgets.
- Composer, Packagist и composer.json и Autoloading и PSR-4 — инфраструктура установки Yii и расширений.
- Laravel, Symfony, Slim и Mezzio, Выбор PHP-фреймворка — соседние варианты в PHP-экосистеме.