Pull to refresh

Comments 14

Только что запустил на PHP 7.0.8, Ubuntu 16.10 x64
Скрытый текст


|framework          |requests per second|relative|peak memory|relative|
|-------------------|------------------:|-------:|----------:|-------:|
|phalcon-2.0        |           8,796.40|     3.2|       0.38|     1.0|
|cleverstyle-5.15   |           2,756.97|     1.0|       0.66|     1.7|
Решил сделать более полный, результаты опять слегка отличаются, но в целом Phalcon не переплюнуть по производительности
Скрытый текст


|framework          |requests per second|relative|peak memory|relative|
|-------------------|------------------:|-------:|----------:|-------:|
|phalcon-2.0        |           8,542.78|    15.0|       0.38|     1.0|
|silex-1.3          |           2,746.60|     4.8|       0.59|     1.6|
|symfony-2.7        |           1,289.42|     2.3|       1.41|     3.7|
|symfony-3.0        |             957.06|     1.7|       1.64|     4.3|
|laravel-5.2        |             570.63|     1.0|       1.98|     5.2|
|zf-2.5             |             707.26|     1.2|       1.36|     3.6|
|cleverstyle-5.15   |           2,459.84|     4.3|       0.66|     1.7|

а никто symfony 2.8+ в режиме микроядра не добавлял?

Я хотел, но он сломан в бенчмарке. Если кто-то исправит, с радостью сравню.
Когда планируете использовать паттерны проектирования, PSR, DI?

PSR поддерживается на уровне совместимости, к примеру, прослойка для PSR7, автозагрузчик аналогичен PSR4 по сути, просто есть несколько директорий с разными префиксами (cs\modules это модули в modules, а cs это системные классы в core\classes), тот же Composer можете использовать.


На счёт DI — нет и не планируется. Во фреймворке он не нужен, ибо он не компонентный и не предполагает свободной замены своих частей. А если вам нужен DI — вон сколько их готовых на GitHub, подключайте чего вам нравится, не вижу пока смысла что-то в этом плане навязывать.


На счёт паттернов — что конкретно вам не нравится? Буду благодарен если ответите конкретно с примером, а то выглядит как вопрос на собеседовании)

no offence, но все на синглтонах — это, на мой взгляд, не комильфо.

Это я часто слышу, попытался ответить на этот вопрос здесь

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

1) что такое "ручное внедрение зависимостей"? Фабрики? Что там нечитабельного?
2) внедрение зависимостей, которые на самом деле не используются означают что у модуля низкая внутренняя связанность и его нужно разделить на отдельные модули. А еще есть lazy инициализация с проксями. Опять же вас никто не заставляет писать свой контейнер — юзаем готовые которые все это умеют и учитывают.


либо локатор сервисов (Service Locator)

какое отношение это вообще к Dependency Injection имеет?


Контейнер внедрения зависимостей

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

неверно. Основная суть что у вас есть один объект в системе, чья задача разруливание зависимостей. Никакой чуши про интерфейсы => реализации.


в противном случае какой толк от конфигурации? Так же этот подход не решает проблемы с ленивым созданием сервисов.

Толк в том что она есть и мы не пишем кучу фабрик. Они генерятся сами. А если вы посмотрите на популярные контейнеры — там в принципе в 80% случаев вообще конфигурацию описывать не нужно.


Сервис локатор

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

ленивая загрузка это не решение проблемы а ее симптом. Ну и про конфигурацию — тупой autowiring делается весьма просто.


очень маловероятно что мы будем писать многопоточное и/или полностью асинхронное приложение

справедливости ради, при использовании pthreads статика не шарится по потокам. Как раз таки как защита от дурака. Расшаривание данных происходит максимально явно и случайно расшарить что-то не выйдет.


То есть по сути, в CleverStyle Framework тот же локатор сервисов, который, тем не менее, не требует никакой конфигурации, поскольку система не предполагает свободной замены системных классов.

Если замена не предполагается (то есть никакой инверсии контроля, никакой гибкости) то как бы и любой другой "локатор" не требует никакой конфигурации. Макретинговая хрень. Да и "сервис локатор это антипаттерн!".


Резюмирую. Сингелтон сам по себе — нормальный паттерн. В PHP мире на нем реализуют сервис локатор, и как бэ вот это и есть "плохо". Вообще любое глобальное — не очень хорошо и давать такое использовать кому попало не стоит.

1) что такое "ручное внедрение зависимостей"? Фабрики? Что там нечитабельного?

Я имел ввиду подобное:


$obj = new SuperClass(new Dependency1(new Dependency2()), new Dependency3());

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


какое отношение это вообще к Dependency Injection имеет?

Достаточно прямое, позволяет вместо кода выше писать подобное:


$obj = $locator->get('SuperService');

А под капотом будут внедрены нужные зависимости.


2) внедрение зависимостей, которые на самом деле не используются означают что у модуля низкая внутренняя связанность и его нужно разделить на отдельные модули. А еще есть lazy инициализация с проксями. Опять же вас никто не заставляет писать свой контейнер — юзаем готовые которые все это умеют и учитывают.

Согласен, но всегда есть граница здравого смысла. Городить прокси просто для того чтобы следовать паттерну, при том что сервис никогда не будет изменен? По-моему овчинка выделки не стоит. По крайней мере я предпочту повышение связности до определённой границы.


неверно. Основная суть что у вас есть один объект в системе, чья задача разруливание зависимостей. Никакой чуши про интерфейсы => реализации.

Это грубо, имеется ввиду что зависимости не черной магией разруливаются, а по определённым образом составленным правилам.


Толк в том что она есть и мы не пишем кучу фабрик. Они генерятся сами. А если вы посмотрите на популярные контейнеры — там в принципе в 80% случаев вообще конфигурацию описывать не нужно.

То есть решаем проблему, которой изначально не было? Сейчас во фреймворке вообще нет фабрик, они просто не нужны. И есть лишь один метод во всём фреймворке, который занимается созданием подобных объектов. autowiring это круто, но это работает не в 100% случаев, а в данном случае решает то, что не является проблемой изначально.


ленивая загрузка это не решение проблемы а ее симптом. Ну и про конфигурацию — тупой autowiring делается весьма просто.

Опять таки да, но проблемы может вообще не быть при альтернативном подходе.


Я пытаюсь донести, что при наличии единственной реализации чего либо в принципе, не вижу смысла в интерфейсах, DI, тащить что-то калибра PHP-DI (который, несомненно, крут, но по объему как 15% всего CleverStyle Framework) и так далее, поскольку это не имеет практического смысла. Гораздо удобнее иметь прямой вызов и автоматический вывод типов в IDE без каких-либо сторонних плагинов, да и производительность получится самая высокая. Если это можно в итоге протестировать и вместе оно хорошо работает — то почему нет?


Не хочется закончить написанием https://github.com/Herzult/SimplePHPEasyPlus либо https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition в реальной жизни.


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

Достаточно прямое, позволяет вместо кода выше писать подобное:

вся суть в том, что "код выше" не требует никаких контейнеров, локаторов и прочего что бы работать. Мы можем "собрать руками", а можем попросить вошлебный контейнер зависимостей сделать это за нас. Суть в том, что если мы вдруг захотим "поменять контейнер" например с симфоневого на PHP-DI или сменить фреймворк (имеется в виду мажерные релизы без сохранения обратной совместимости), наши "классы" не будут фигурировать в diff-ах наших коммитов на эту тему.


Сервис локатор — это полная завязанность на текущем способе разруливания зависимостей. Это нормально только там, где это нормально (контроллеры например, они и так часть фреймворка и завязаны на нем) либо если вы пишите что-то что собираетесь удалить через пару месяцев. Что все должно "жить" более пары лет — не должно быть так сильно завязано на способ разруливания зависимостей.


Все сводится к принципу "работает не трогай", или как я его трактую — "делай так, что бы не пришлось потом менять, только удаляй/добавляй классы".


Городить прокси просто для того чтобы следовать паттерну, при том что сервис никогда не будет изменен?

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


А зачем и когда нужно следовать "паттерну" — я описал выше.


Это грубо, имеется ввиду что зависимости не черной магией разруливаются, а по определённым образом составленным правилам.

разруливание по правилам = магия. Она такая же "черная" но чуть другая.


То есть решаем проблему, которой изначально не было?

проблема управления зависимостями и управление связанностью существует… ну скажем так, она появилась раньше чем ООП. В каком-то смысле ООП является решением этой проблемы.


Я пытаюсь донести, что при наличии единственной реализации чего либо в принципе, не вижу смысла в интерфейсах, DI, тащить что-то калибра PHP-DI

вы этим как бы говорите "у меня всегда будет только одна реализация, и не только у меня — у всех кто будет использовать мою систему!". То есть вы не даете никакой возможности для кастомизации.


Не хочется закончить написанием

Вы из одной крайности (все жестко) бросаетесь в другую (отсутствие здравого смысла). Вы же понимаете что… все должно быть в балансе.

Sign up to leave a comment.

Articles