Поговорим о Yii 2

в 16:10, , рубрики: laravel, php, symfony, yii, yii2, ооп

Yii, вероятно, самый популярный PHP фреймворк на просторах СНГ.
Многие годы он был замечательным инструментом и помогал нам зарабатывать на хлеб с маслом.
Но стоит ли начинать на нем новые проекты в 2017-м? Я задумался.

Архитектура фреймворка

Мысленно вернемся в 2014-й.
Ожидание второй версии Yii кажется бесконечно долгим, core-разработчики не называют никаких сроков.
Разработка ведется в закрытом от публики репозитории.

И вот SamDark презентует Yii 2.0:

После трёх лет интенсивной разработки...
Как вы, возможно, уже знаете, Yii 2.0 был переписан с нуля.

Выходит, архитектура закладывалась в 2014 — 3 = 2011-м году. Или раньше?

Взгляните на Component.php из Yii 2
А теперь на CComponent.php из Yii 1
А теперь на TComponent.php из PRADO Framework — дедушки нынешнего Yii. Выглядит знакомо.

Истоки самого же PRADO уходят куда-то во времена расцвета Delphi:

The very original inspiration of PRADO came from Apache Tapestry.
During the design and implementation, Qiang Xue borrowed many ideas from Borland Delphi and Microsoft ASP.NET.
The first version of PRADO came out in June 2004 and was written in PHP 4.

С первой версии нам достались глобальные константы в коде, свой autoloader, своя хитрая система алиасов для файлов и папок.

Ооооок. Просто напоминаю, что сейчас идет вторая половина 2017-го.

Приходя к Yii с других инструментов, вы должны понимать, что здесь весь ваш предыдущий опыт становится нерелевантным.
Yii — это не просто фреймворк, это попытка сделать свою надстройку над языком.
Все, абсолютно все компоненты Yii наследуются от класса Object, в котором переопределяются __get, __set, __isset и так далее.

Многие классы наследуются от Component, который наследуется от Object, и в котором еще раз переопределяются все магические методы.

Благодаря этому все классы фреймворка из коробки умеют бросать события, подписываться на них, могут содержать т. н. behaviors.
Каждая модель ActiveRecord в вашем приложении неявно наследует 5 классов и реализует 5 интерфесов.
У всех ваших моделей, так называемых "компонентов", "виджетов", контроллеров, логгеров, хелперов, валидаторов — одни и те же предки.
image

Компоненты, их события, поведения… возможно, они имели смысл в PRADO Framework, где "компонентами" были TButton, TAccordion и все вот это.

Среди достоинств Yii часто озвучивают простоту фреймворка. Но это правда только отчасти.
Знаете, что происходит, когда вы делаете что-то безобидное вроде $post->title = 'Hello'?
Вы можете побывать здесь, здесь, здесь, здесь, а также в любом прикрепленном к $post event-у или behavior-у.

Это может свести с ума во время отладки.

Не добавляет радости и тот факт, что любой компонент приложения из любого места можно достать через Yii::$app. Эдакий экземпляр приложения и сервис-локатор в одном лице.

DI-контейнер

В Yii 2 он есть.
В нем нет ни compile-time проверок, ни защиты от circular references, ни тегов (как в Symfony и Laravel), ни Contextual Binding (как в Laravel).
Доступен из любой точки приложения как Yii::$container. Снова.
Внутри Yii 2 собственный контейнер не используется, а все компоненты лежат в Yii::$app, прямо как в первой версии.

Интересный факт: Qiang начал писать Yii 2 в 2011 году, а контейнер был добавлен только три года спустя, между 2.0.0-alpha и 2.0.0-beta.

Active Record

Если оставить в стороне споры Active Record vs Data Mapper, то реализация AR в Yii очень даже ничего.
Удобное и лаконичное API, поддерживаются все популярные СУБД. Есть нормальные миграции из коробки.

Единственный минус вытекает из сильной связанности фреймворка — если ваша бизнес-логика оказалась в AR-моделях, то переиспользовать все это добро можно только в рамках проектов на Yii.

Фронтенд

Тут все плохо.
В Laravel есть Elixir, в Symfony с недавних пор — Webpack encore.
Yii же не просто не помогает с фронтендом, а еще и добавляет головной боли.

Для установки Yii 2 вам нужно в принудительном порядке поставить глобально fxp/composer-asset-plugin, для того, чтобы поставить jQuery c помощью composer-а, для того, чтобы установился Yii.

jQuery входит в обязательные зависимости Yii 2.

Не припоминаю ни одного другого composer-пакета, для установки которого нужно было танцевать с бубном.
В проектах с Yii каждый запуск composer install/update происходит утомительно долго,
т.к. composer каждый раз идет гулять куда-то в глубины репозитория Bower-пакетов.
Еще мне когда-то пришлось откатывать версию composer-а на более старую, из-за несовмесимости с текущей версией fxp/composer-asset-plugin.

В качестве альтернативы предлагается использовать дополнительный composer-репозиторий, который кеширует npm и bower пакеты. Что тоже выглядит немного костыльно.

Если знаете, как поставить Yii без возни с ненужными фронтенд-пакетами — пишите в комментариях.

Все остальные компоненты

Абстракция над HTTP, кеширование, логирование… они есть, и они без проблем выполняют свои задачи.
Конечно же они самобытные, гвоздями прибитые к Yii, и не имплементируют соответствующие им PSR-ы.

Будущее Yii

Скорость развития оставляет желать лучшего

Помните, как долго мы ждали версию 2.0?
А вы знаете, когда выйдет 2.1? Никто не знает.

2.0.x: 222 открытых тикета — No due date.
2.1.0: 58 тикетов — No due date.
2.2.x: 1 тикет — No due date.

Т.е. для 2.1 еще не определена дата релиза, а для 2.2 даже примерный скоуп задач. До третьей версии, о которой еще рано даже начинать говорить, мы вряд ли увидим кардинальные изменения в архитектуре.

Следует признать, что ближайшие конкуренты — Laravel и Symfony — внедряют новые фишки и выпускают версии гораздо резвее. У обоих конкурентов уже есть LTS-версии. Yii 2.1 вроде бы тоже должна иметь long-term support.

Компонентные фреймворки победили

Если кто-то напишет хорошее расширение для Yii — оно не выйдет за пределы комьюнити Yii.
Библиотека же, которую можно подключить без бубна к любому проекту, может улучшаться кем угодно.

Код, написанный на PHP, работает везде, а код, написанный на Yii — только на Yii.
Вы либо ставите на Yii всё, либо ничего. Это риск для долгосрочного проекта.

Конечно, приложив усилия, можно писать framework-agnostic код и разруливать все через DI-контейнер, но это не поощряется.
Если вы все-таки решитесь на это, вам прийдется забыть про Yii-вский ActiveRecord
или начать писать неприлично толстые прослойки между фреймворком и вашей бизнес-логикой.
Но это, мягко говоря, неоправданно.

Если вы наследуете какой-либо класс своего приложения от любого другого класса Yii, без Yii вы его работать не заставите, ведь он обязательно наследует Object или Component. Вот.
Даже если вы вытащите вместе с ним весь ворох родительских классов и реализуемых интерфейсов, это вам не поможет.
С модными нынче DDD и CQRS/Event Sourcing Yii также вам не помощник. Скорее, даже будет вставлять палки в колеса.

Команда фреймворка всё пишет сама. Даже VarDumper они написали свой, а не взяли из компонентов Symfony.
Регулярно поддерживать и улучшать столько компонентов — очень непростая задача для небольшой команды. И у этой команды есть два пути.

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

Во-вторых, можно все-таки разбить монолитный Yii на независимые от фреймворка компоненты.
Но тогда это будет уже не Yii с простым и удобным API, а просто еще один набор компонентов, не востребованный вне экосистемы Yii.

Оба пути ведут в никуда.

PHP 7

Yii 2 без проблем работает под PHP 7+.
Однако чтобы использовать все возможности type-hinting-а, core-разработчикам придется переписать его до неузнаваемости.
Дело в том, что сейчас много методов принимают аргументы нескольких типов:

// Поиск записи по первичному ключу со значением "42"
SomeModel::findOne(42);

// так тоже работает
SomeModel::findOne(['id' => 42]);

// Вернет первую найденную запись, у которой PK - одно из значений переданного массива
SomeModel::findOne([1, 2, 3]);

// и так можно
Url::to(['site/index']);

// и так
Url::to('images/logo.gif');

// или вот
$relativeBaseUrl = Url::base();
$absoluteBaseUrl = Url::base(true);
$httpsAbsoluteBaseUrl = Url::base('https');

Таких мест в фреймворке очень много. Кого-то это бесит, кто-то считает это API удобным.
Но если мы хотим использовать тайпхинтинг, все это удобное API превращается в тыкву.

Qiang так и не вернулся

Полтора года назад на форуме Yii подняли интересный вопрос, мол, не забил ли Qiang Xue на свое детище?
Как бы там ни было, с тех пор от него так и не пришло ни одного коммита.

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

Что в итоге

Yii — неплохой инструмент и если вам с ним комфортно — отлично.
В конце-концов, он практичен. Трудно представить задачу, которую невозможно решить, используя Yii.
Еще Yii невероятно популярен в СНГ. Зная его, очень легко найти как работу, так и сотрудников.

Но если у вас намечается новый долгосрочный проект, обязательно рассмотрите альтернативы.
Не выбирайте инструмент только из-за привычки.

Кроме того, вы всегда можете помочь команде фреймворка. Присылайте внятные баг-репорты, отправляйте пул-реквесты, пишите качественные расширения, помогайте новичкам на форуме и в gitter-е.

Может быть, Yii еще покажет себя ;)

Автор: Roman Vasilyev

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js