При разработке любого программного продукта перед командой разработчиков прежде всего стоит задача грамотного выбора программной платформы, определяющей структуру программной системы.

Для этого нужно учесть достаточно большое количество характеристик, от «как быстро всё будет работать» до «а необходима ли нам эта фича?». И так каждый раз. Именно в моменты мозгового штурма команда сравнивает удобство фреймворка, скорость, набор фич, которые реализованы в нем или в совместимых с ним модулях.

Но какой же всё-таки лучше, быстрее и производительнее?

Разработчики постоянно проводят сравнение фреймворков, чтобы прояснить для себя этот вопрос. Например, в статье Lukasz Kujawa приведено сравнение PHP фреймворков. Одно «но» — статья за 2013 год. А ведь время идёт… Поэтому мы решили провести своё, актуальное сравнение фреймворков.

Для оценки производительности был использован PHP Framework Benchmark. Он предлагает для сравнения множество фреймворков (не только указанных выше), но автор не спешит добавлять в репозиторий новые версии проектов, что, конечно же, печально, хотя и не смертельно. При желании добавить новую версию не сложно. ?

Одной из основных целей данной статьи также является попытка практическим путем определить улучшения в производительности и эффективности новых версий PHP. Поэтому тестирование было проведено на РНР 5.6/7.0/7.1

Что будем сравнивать?


Для сравнения были выбраны следующие фреймворки:

  • slim-3.0
  • ci-3.0
  • lumen-5.1
  • yii-2.0
  • silex-1.3
  • fuel-1.8
  • phpixie-3.2
  • zf-2.5
  • zf-3.0
  • symfony-2.7
  • symfony-3.0
  • laravel-5.3
  • laravel-5.4
  • bluz (версия 7.0.0 — для РНР5.6 и версия 7.4 для РНР7.0 и выше)
  • ze-1.0
  • phalcon-3.0

Тестирование условно разделено на 4 вида:

  • производительность (throughput),
  • занимаемая память (memory),
  • время выполнения (exec time),
  • количество подключаемых файлов (included files).

Методика тестирования и тестовый стенд


Машина, на которой производилось тестирование, обладает следующими характеристиками:

Operation system: Linux Mint 17 Cinnamon 64-bit
Cinnamin Version 2.2.16
Linux Kernel: 3.13.0-24-generic
Processor: Intel Core i3-4160 CPU 3.60 Ghz X 2
Memory: 8 GB

Server version: Apache/2.4.7 (ubuntu)
Server build: Jul 15 2016
php 7.1 / php7.0 / php5.6


Вводим команду git clone https://github.com/kenjis/php-framework-benchmark — и фрейм уже на нашей машине. Поскольку мы использовали Mint, необходимо выполнить настройку: ?

# Added?net.netfilter.nf_conntrack_max = 100000?net.nf_conntrack_max = 100000?net.ipv4.tcp_max_tw_buckets = 180000?net.ipv4.tcp_tw_recycle = 1?net.ipv4.tcp_tw_reuse = 1?net.ipv4.tcp_fin_timeout = 10

sudo sysctl -p


Немного о структуре самого php-framework-benchmark:

/benchmarks — содержит bash-скрипты, отвечающие за сбор информации о количестве запросов в секунду (при помощи утилиты ab), количестве информации, сколько времени было потрачено и сколько файлов вызывалось из файла «точки старта».

/lib — директория, в которой находятся файлы, отвечающие за обработку полученной информации после вывода страницы “Hello world”, вывод таблиц с результатами и построение диаграмм.

/output — директория, в которую добавляются логи после выполнения тестирования. Здесь находится по два файла для каждого протестированного файла: .ab.log — лог после работы утилиты ab, и .output — содержит информацию, которая была выведена на экран (обычно это hello world и данные по памяти, времени выполнения, использовавшимся файлам).

Остальные папки — это заготовки фреймов, в которые уже добавлен один контроллер, который вернет строку “hello world” при обращении по URI, составленному по правилам обращения к данному фреймворку.

Для запуска теста сначала нужно настроить фреймворки. Рассмотрим два подхода.

Команда bash setup.sh настроит те фремворки, которые описаны в файле list.sh. Вы можете его редактировать: добавлять и удалять папки для тестирования. То есть конфигурировать так, как вам необходимо.

Командой bash setup.sh fatfree-3.5/ slim-3.0/ lumen-5.1/ silex-1.3/ вы можете установить какие-то отдельные фреймворки, задав их параметрами к команде. В некоторых случаях это удобно, но мы использовали первый подход.

После произведенной настройки фреймворков, мы запустили тестирование при помощи bash benchmark.sh.

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

Для отображения графиков мы воспользовались ссылкой http://localhost/php-framework-benchmark/.

Как вы понимаете, необходимо было произвести настройку Apache и заставить его смотреть в папку с фреймом. Всё это описано в readme, поэтому вопросов не возникает.
?

Результаты тестирования фреймворков


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

Первая форма — это наглядный тип представления. Каждая характеристика содержит 4 диаграммы. Каждая диаграмма отображает сравнение фреймворков между собой, плюс накопительная диаграмма. Она была построена при использовании определенной версии РНР. Таким образом можно проследить эволюцию улучшений в PHP и фреймворках.

Вторая форма — это результат тестирования в виде таблицы (хватить наглядности, давайте говорить серьезно — дайте мне больше чисел!).

Производительность (throughput)


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

Мы получили следующие результаты (запросы в секунду):
php 5.6 php 7.0 php 7.1
phalcon-3.1.2 5058.00 5130.00 7535.00
ci-3.0 2943.55 4116.31 4998.05
slim-3.0 2074.59 3143.94 3681.00
yii-2.0 1256.31 2276.37 2664.61
silex-1.3 1401.92 2263.90 2576.22
lumen-5.1 1316.46 2384.24 2741.81
ze-1.0 1181.14 1989.99 1741.81
phpixie-3.2 898.63 1677.15 1896.23
fuel-1.8 1044.77 1646.67 1770.13
bluz-7.3.1 — * 1774.00 1890.00
zf-2.5 198.66 623.71 739.12
zf-3.0 447.88 1012.57 1197.26
symfony-2.7 360.03 873.40 989.57
symfony-3.0 372.19 853.51 1022.28
laravel-5.3 258.62 346.25 625.99
laravel-5.4 219.82 413.49 600.42

* — bluz-7.3.1 не поддерживает php 5.6

Для наглядности построили графики для каждой версии PHP:

PHP5.6:


PHP7.0:


PHP7.1:


Сводная накопительная диаграмма (по фреймворкам):


Занимаемая память (peak memory)


Эта характеристика (в мегабайтах) отвечает за количество занимаемой фреймворком памяти при выполнении поставленной перед ним задачи. Чем меньше данное число, тем лучше для нас и для сервера:
php 5.6 php 7.0 php 7.1
phalcon-3.1.2 0.27 0.38 0.37
ci-3.0 0.42 0.38 0.38
slim-3.0 0.61 0.55 0.55
yii-2.0 1.31 0.91 0.91
silex-1.3 0.74 0.65 0.65
lumen-5.1 0.80 0.63 0.63
ze-1.0 0.79 0.56 0.56
phpixie-3.2 1.22 0.82 0.82
fuel-1.8 0.7 0.6 0.6
bluz-7.3.1 — * 0.69 0.69
zf-2.5 3.06 1.34 1.34
zf-3.0 2.12 1.09 1.08
symfony-2.7 3.11 1.41 1.42
symfony-3.0 2.86 1.30 1.32
laravel-5.3 2.91 2.04 2.04
laravel-5.4 3.04 1.45 1.49

* — bluz-7.3.1 не поддерживает php 5.6

PHP 5.6:


PHP 7.0:


PHP 7.1:


Сводная накопительная диаграмма (по фреймворкам):


Время выполнения


Время выполнения — время, затрачиваемое системой для выполнения поставленной задачи. Измеряется от начала выполнения задачи до выдачи результата системой.


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

Время приведено в миллисекундах (ms):
php 5.6 php 7.0 php 7.1
phalcon-3.1.2 1.300 1.470 1.080
ci-3.0 0.996 0.818 1.007
slim-3.0 1.530 1.228 0.662
yii-2.0 1.478 1.410 1.639
silex-1.3 4.657 1.625 2.681
lumen-5.1 2.121 1.829 1.228
ze-1.0 2.629 2.069 1.528
phpixie-3.2 9.329 4.757 1.911
fuel-1.8 3.283 2.684 1.425
bluz-7.3.1 — * 1.619 1.921
zf-2.5 22.042 5.011 3.998
zf-3.0 12.680 2.506 2.989
symfony-2.7 6.529 3.902 2.384
symfony-3.0 9.335 3.987 2.820
laravel-5.3 19.885 4.840 2.622
laravel-5.4 19.561 4.758 3.940

PHP 5.6:


PHP 7.0:


PHP 7.1:


Сводная накопительная диаграмма (по фреймворкам):


Подключаемые файлы


Характеристика, отвечающая за количество подключаемых файлов, которые описаны в файле «точки входа» фреймворка. Понятно, что система тратит какое-то время на поиск и подключение. Следовательно, чем меньше файлов, тем быстрее будет осуществляться первый запуск приложения, так как обычно в последующие разы фреймворк работает с кэшем, что ускоряет работу:
phalcon-3.1.2 5
ci-3.0 26
slim-3.0 53
yii-2.0 46
silex-1.3 63
lumen-5.1 37
ze-1.0 68
phpixie-3.2 163
fuel-1.8 53
bluz-7.3.1 95
zf-2.5 222
zf-3.0 188
symfony-2.7 110
symfony-3.0 192
laravel-5.3 38
laravel-5.4 176



Разница в количестве подключаемых файлов между Laravel 5.3 и Laravel 5.4 может показаться странной и дать повод к обсуждениям, спорам и т.п. Спешим разъяснить ситуацию. Как вы знаете, с помощью команды

php artisan optimize --force

в Laravel 5.3 можно сгенерировать файл compiled.php, и тем самым уменьшить количество подключаемых файлов, собрав их в один. Но есть одно «но»: команды для генерации этого файла в Laravel 5.4 больше нет. Разработчик решил удалить эту фичу, так как посчитал (https://github.com/laravel/framework/pull/17003), что для настройки производительности лучше использовать opcache.

Стоит ли обновляться?


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

При переходе с PHP 5.6 на PHP 7.0 средний прирост производительности составил почти +90%, при этом минимальный прирост производительности составил +33% для Laravel 5.3, а максимум — >200% для Zend Framework 2.5.

Переход с версии 7.0 на 7.1 уже не так шокирует, но всё же в среднем даёт почти 20% прирост производительности.

Сведя все полученные данные по производительности различных версий PHP, получим вот такие «матрасы»:

Забавный факт: Laravel 5.3 показал наименьший прирост производительности при миграции с PHP 5.6 на PHP 7.0, но при этом наибольший прирост при миграции с версии 7.0 на версию 7.1, и как итог — производительность Laravel 5.3 и 5.4 на PHP 7.1 практически одинакова.

Потребление памяти тоже оптимизировали, так что переход с PHP 5.6 на PHP 7.0 позволит вашему приложению потреблять на 30% меньшем памяти.

Обновление с версии 7.0 до версии 7.1 практически не даёт прироста, а в последних Symfony и Laravel так и вовсе уходим в «минус», потому что они начинают чуть больше «кушать».

Осталось ещё посмотреть на время выполнения, и да, тут тоже всё отлично:

  • переезд с PHP 5.6 на PHP 7.0 подарит вам ускорение в среднем на 44%.
  • переезд с PHP 7.0 на PHP 7.1 подарит вам ускорение ещё на 14%.


Примечание. Тестирование при помощи ab — с чем мы столкнулись




«А что со slim и phpixie» — этот вопрос подтолкнул на расследование поведения утилиты ab при взаимодействии с этими фреймворками.

Выполним тест отдельно для Slim-3.0:

ab -c 10 -t 3 http://localhost/php-framework-benchmark/slim-3.0/index.php/hello/index

Concurrency Level: 10
Time taken for tests: 5.005 seconds
Complete requests: 2
Failed requests: 0
Total transferred: 1800 bytes
HTML transferred: 330 bytes
Requests per second: 0.40 [#/sec] (mean)
Time per request: 25024.485 [ms] (mean)
Time per request: 2502.448 [ms] (mean, across all concurrent requests)
Transfer rate: 0.35 [Kbytes/sec] received


Что-то не так — количество запросов в секунду всего 0.4 (!)

ab -c 10 -t 3 http://localhost/php-framework-benchmark/laravel-5.4/public/index.php/hello/index

Concurrency Level: 10
Time taken for tests: 3.004 seconds
Complete requests: 1961
Failed requests: 0
Total transferred: 1995682 bytes
HTML transferred: 66708 bytes
Requests per second: 652.86 [#/sec] (mean)
Time per request: 15.317 [ms] (mean)
Time per request: 1.532 [ms] (mean, across all concurrent requests)
Transfer rate: 648.83 [Kbytes/sec] received


Дело было в Keep Alive соединении, подробнее можно узнать тут.

“When you make requests with «Connection: keep-alive» the subsequent request to the server will use the same TCP connection. This is called HTTP persistent connection. This helps in reduction CPU load on server side and improves latency/response time.

If a request is made with «Connection: close» this indicates that once the request has been made the server needs to close the connection. And so for each request a new TCP connection will be established.

By default HTTP 1.1 client/server uses keep-alive where as HTTP 1.0 client/server don’t support keep-alive by default.”

Таким образом, тест для Slim должен выглядеть так:

ab -H 'Connection: close' -c 10 -t 3 http://localhost/php-framework-benchmark/slim-3.0/index.php/hello/index

Concurrency Level: 10
Time taken for tests: 3.000 seconds
Complete requests: 10709
Failed requests: 0
Total transferred: 2131091 bytes
HTML transferred: 353397 bytes
Requests per second: 3569.53 [#/sec] (mean)
Time per request: 2.801 [ms] (mean)
Time per request: 0.280 [ms] (mean, across all concurrent requests)
Transfer rate: 693.69 [Kbytes/sec] received


Заключение


Как и стоило ожидать безоговорочным лидером по производительности (но не скорости разработки) является Phalcon. Второе место, — а на самом деле первое среди PHP-фреймворков (а не C, на котором написан исходный код Phalcon) — занимает CodeIgniter 3!

Конечно же, не стоит забывать, что каждому инструменту своё предназначение. Если вы выбираете небольшой и легкий фреймворк и собираетесь написать на нём что-то отличное от простейших приложений или REST API, то, скорее всего, вы столкнётесь с проблемами при расширении функционала. И наоборот — избыточность полнофункциональных, больших фреймворков повлечёт за собой финансовые издержки на содержание хостинга даже для элементарных приложений под большой нагрузкой.

Это тестирование проводилось для того, чтобы убедить/рассказать/укрепить позицию языка РНР версий 7.0 и 7.1 в вашем сознании и в будущих проектах, донести информацию о том, что производительность действительно возросла.

Рефакторинг внутренних структур данных и добавление дополнительного этапа перед компиляцией кода в виде абстрактного синтаксического дерева — Abstract Syntax Tree (AST), — привели к превосходной производительности и более эффективному распределению памяти. Результаты сами по себе выглядят многообещающе: тесты, выполненные на реальных приложениях, показывают, что PHP 7 в среднем вдвое быстрее PHP 5.6, а также использует на 50% меньше памяти во время обработки запросов, что делает PHP 7 сильным соперником для компилятора HHVM JIT от Facebook.

Тесты полностью подтверждают и вдвое ускорившуюся обработку запроса в РНР7, и уменьшенное количество используемой памяти.
Поделиться с друзьями
-->

Комментарии (54)


  1. Caelwyn
    30.05.2017 10:51
    +1

    Phalcon начиная со второй версии написан на зефире (тот-же PHP с некоторыми дополнениями, и компилируемый), а не на си. Так что проблемы могут возникнуть разве что только с отладкой фреймворка, если что-то пошло не так. И скорость разработки с кривой входа у него ничем не отличается от ларавеля, всё то-же самое.


  1. Exileum
    30.05.2017 11:16
    +5

    Тестирование коней в вакууме. В этом списке не хватает только чистого php, без фреймворков вообще. Есть ощущение что в таком случае он уделает вообще всех. Вот только напишите сложное бизнес-приложение на
    Symfony, например, а потом полные аналоги на всех остальных фреймворках — а потом проверьте что быстрее будет. Останется ли CodeIgniter вообще в этом списке — тот еще вопрос.


    1. OnYourLips
      30.05.2017 21:29

      Стоит сделать оценку производительности разработки в фичах при возрасте проекта в пару десятков человеколет.
      И что-то мне подсказывает, что symfony на порядки будет обходить остальные варианты.


  1. ellrion
    30.05.2017 11:38
    +5

    Убедили, бросаю Laravel и перехожу на CodeIgniter.


    1. 7u7u
      31.05.2017 12:29

      Перед тем как бросить Laravel лучше попробуйте создать на CodeIgniter'е веб-приложение. После этого вам вряд ли захочется переехать на CodeIgniter. Ребята из CodeIgniter'а всё ещё не понимают что такое ООП. Даже в 3ей версии всё ещё нет неймспейсов.


      1. ellrion
        31.05.2017 13:03
        +2

        Вы слишком серьезны). Мой коммент носил явный саркастический характер.


  1. iqw
    30.05.2017 12:31
    +2

    Меня смутило, что все тесты проводились, по факту, только со стеком компонентов, которые задействованы в роутинге (загрузить контроллер, отдать респонз), большая часть толковых фреймворков сейчас все лейзи лоадом подтягивает, того, имхо, 80% системы не было затронуто этим простеньким тестом


    1. Fesor
      31.05.2017 20:29

      Зато быстро можно сострапать статью. Сравнение количества подключаемых файлов это вообще дичь.


  1. sayber
    30.05.2017 12:48
    +2

    Меня всегда радуют подобные бесполезные тесты и сравнения.
    Вот если бы на каждом из фреймворков был реализован какой то тяжелый механизм, и на нем протестировано, то было бы намного лучше.
    Берем фреймфорк, реализуем структуру DDD/CQRS/CommanBus, вешаем RESTful API, создаем сущности с 10 мил. записей. Каждая запись имеет связь с пятью сущностями (каждая сущность еще 5кк записей), имеет периоды дат.
    Делаем выборку по периоду х — y с связими и т.д.

    В итоге получаем полезную информацию:
    1) Скорость разработки
    2) Костыльность
    3) Скорость выборки
    4) Скорость обработки
    5) Возможности фреймворка


    1. vlreshet
      30.05.2017 14:11

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


  1. oxidmod
    30.05.2017 12:49
    +2

    Стоило добавить симфони в режиме микро ядра. А то не очень прикольно сравнивать микрофреймворки с фулл-стек фреймворком


    1. skobkin
      31.05.2017 05:32
      +1

      И тестовую версию с Symfony Flex тогда уж. Фабьен говорил, что за счёт нововведений в будущей четвёртой ветке производительность ещё вырастет.


  1. san4ez
    30.05.2017 12:59
    +1

    Не до конца понятен выбор версий для Symfony. Если ходили по LTS версиям фреймворков, то почему 2.7, а не 2.8? Если не LTS, то почему 3.0, а не 3.2? Как-то обидно за фреймворк.


    1. skobkin
      31.05.2017 05:33

      3.0 тоже не LTS. То есть, выбор странный в любом случае.


  1. http2
    30.05.2017 17:07
    -9

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

    По такой методике фреймворк будут выбирать лишь олени.


    1. negasus
      30.05.2017 22:38
      +2

      Ну и ад же по ссылке. Автора не то что переубедить, даже поколебать невозможно. Несмотря на явные случаи нарушения банальной логики.
      Сейчас, небось, скажет, что и минусуют его тоже «олени».


      1. http2
        31.05.2017 10:05
        -1

        Сейчас, небось, скажет, что и минусуют его тоже «олени».

        А кто же минусует тогда? :)

        Вы хотите сказать, что по хабровчанской статье можно выбирать фреймворк? :)

        А какие в той статье нарушения логики?
        Можете откомментить, статья постоянно улучшается.
        Если сейчас ад, то ранее был ад в квадрате. :) Статья все же улучшилась.


        1. Fesor
          31.05.2017 20:40

          Вы хотите сказать, что по хабровчанской статье можно выбирать фреймворк? :)

          Их нужно выбирать не по статьям с просто берешь что лучше знаешь и где проще найти разработчиков/проекты. Далее в дело еще география подключается. Если мы говорим про европу — Symfony. Штаты — Laravel. Параметров для выбора много, но идея в том что в целом с большего все они (если брать популярные) похожи настолько что переход с одного на другой просто не заметите.


          А какие в той статье нарушения логики?

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


          Фреймворки рассчитаны на запуск одного контроллера на страницу

          Какието да, а какие-то нет. Возьмите symfony, там вы можете скомпоновать страницу из отдельных блоков, у каждого из которого будет свой контроллер (ну и общий контроллер для страницы). Выйдет вполне себе граф компонентов.


          Или вот еще рядышком:


          Необходимость в коде контроллера вызывать рендеринг вида явно

          явное всегда лучше неявного. Однако популярные фреймворки (например symfony) предоставляют из коробки декораторы над контроллерами которые сами экспоузнут результат работы контроллера в шаблон (аннотация @Template). Ну и никто не мешает вам это сделать самому на любом другом фреймворке.


          Или вот еще золото:


          Давайте тогда вернем register_globals.

          в контексте рендринга шаблонов звучит это мягко скажем дико.


          Чтобы обратиться к GET/POST/COOKIE/SERVER нужно использовать непойми зачем неудобные обертки

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


          1. kruslan
            31.05.2017 20:55
            +1

            Не ведись… Он либо реально туп, либо сильно троллит. Уже 5-й или 6-й аккаунт у него и всегда одно и то-же.


            1. Fesor
              31.05.2017 23:39
              +1

              Да я вкурсе)


            1. springimport
              05.06.2017 21:34

              Зато весело читать комментарии. Все же надеюсь что человек придет к правильным вещам.


              1. kruslan
                05.06.2017 23:15

                Если-бы не спам ссылками на бред — сам-бы веселился… А так…


          1. http2
            01.06.2017 10:43

            Параметров для выбора много, но они (если брать популярные) похожи настолько, что переход с одного на другой просто не заметите.

            Да потому что и фреймворк-то и не нужен. :)
            Ведь где происходит основная возня с кодом?
            В обработке данных проекта и их выводе.
            Этой возней можно заниматься хоть на CMS, хоть на самописи. :)

            Какие параметры еще есть, кроме популярности в регионе? :)

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

            О, норм я не знал. :) Я же не буду проверять все фреймворки. В документации этот вопрос не освещался вроде ранее.
            Ну, это то чего мне не хватало.
            А до Вас за 2 года никто об этом не сказал.
            (Сказали только, что можно ~полукостыльно, но это нежелательно якобы из-за дикого оверхеда).
            Может это появилось недавно, после прочтения моей статьи? :)

            явное всегда лучше неявного.

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

            Однако популярные фреймворки (например symfony) предоставляют из коробки декораторы над контроллерами которые сами экспоузнут результат работы контроллера в шаблон (аннотация Template).

            То есть имеем одноразовые контроллеры, которые умеют рендерить только 1 шаблон?
            А как же все рассказы об MVC? :)

            Давайте тогда вернем register_globals.
            в контексте рендринга шаблонов звучит это мягко скажем дико.

            extract() делает примерно то же, что и register_globals :)
            Вместо работы с массивов подсовывает переменные с именем, взятым из ключей массива.

            то есть мы против register_globals но при этом любим суперглобальные переменные

            А одно мешает другому? :)

            Ибо просто глобальный стэйт вам ок.

            А не всегда глобальное состояние это плохо.
            Можно же обратиться к «состоянию» приложения?
            В том же Yii 1.1 параметры так работают.

            Ну и какой смысл не использовать GPCS, если под оберткой все равно работа с GPCS? :)
            Я не говорю, что всегда лучше работать напрямую с GPCS. Иногда можно использовать свою обертку.

            П.С.
            А документация и продвижение фреймворков разве не расчитано на дебилов? :)

            П.П.С.
            Всем ораторам.
            Читайте внимательно. Я никому не запрещаю пользоваться фреймворками!
            Я лишь привожу свой опыт, что можно обойтись и без них.


            П.П.П.С.
            Кстати, статья дополнилась 2 пунктами недостатков в самом начале.
            Суть примерно такая: Not invented here. :)


            1. oxidmod
              01.06.2017 11:19
              +1

              Вот одного не пойму, зачем делать самому на самописи то, что можно не делать взяв нормальный фреймворк?


              1. Fesor
                01.06.2017 11:32

                ну автор же сам в предыдущем комментарии описал свою проблему — NIH синдром.


    1. kruslan
      31.05.2017 13:10

      Да как ты постоянно регаешь новые аккаунты-то? Boomburum, этот олень уже достал…


    1. Dimash2
      31.05.2017 13:43

      У вас какая-то проблема с понятием контроллера во фреймворках.

      «У меня виджеты и контроллеры — одна сущность. Примерно как компоненты в Битриксе. Любой компонент может вызвать другой компонент.»

      Что вам мешает так же работать? Просто отстаньте от контроллеров, контроллер контролирует страницу, логику из него следует убрать и сделать из него простой включатель/выключатель


      1. http2
        31.05.2017 16:28

        С $_POST работать в модели? :)
        Или в модель передавать параметром суперглобал $_POST? :)


        1. ellrion
          31.05.2017 16:50
          +1

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


        1. michael_vostrikov
          31.05.2017 21:17
          +1

          Я попытался понять, что вы имеете в виду, и наверно даже понял.
          Задача контроллера применительно к web это обработка связи запрос-ответ (включая заголовки).
          Поэтому у вас в контроллере должны каким-то образом быть понятия request и response.
          Но если вам пофиг на ООП, вместо request можно работать напрямую с $_GET и $_POST.
          Надо выбирать из этих $_GET и $_POST нужные данные и передавать их в модель/сервис/что-то-еще, что реализует бизнес-логику.
          Работать с $_POST в модели не надо.
          Передавать параметром $_POST в модель не надо.
          Бизнес-логику в контроллерах писать не надо.


          1. http2
            01.06.2017 09:41

            Бинго!

            Но если вам пофиг на ООП, вместо request можно работать напрямую с $_GET и $_POST.

            Это все детали.

            Надо выбирать из этих $_GET и $_POST нужные данные и передавать их в модель/сервис/что-то-еще, что реализует бизнес-логику.
            Бизнес-логику в контроллерах писать не надо.

            Ну вот.
            А это будет как бы и не бизнес логика.
            Это как раз будет построение параметров для «модели».
            А так как от модели никакая другая логика кроме выполнить запрос и отдать данные не требуются, то можно из контроллера вызвать нужный метод сущности и все. :)

            П.С.
            Статья чуток изменена касательно буквы М.
            Код, касающийся модели можно размещать в контроллере, если он простой и нету дублирования.


            1. Fesor
              01.06.2017 11:17

              Это как раз будет построение параметров для «модели».

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


              А так как от модели никакая другая логика кроме выполнить запрос и отдать данные не требуются

              Вся проблема в слове "модель". Вот вам чуть-чуть более детализированное представление о том что такое MVC. Для начала посмотрим на вариант того что БЫЛО раньше, во времена десктопов, когда у нас UI layer имеет свой жизненный цикл. Если упрощенно, возьмем виджет для отображения вашего баланса. На этом виджете так же есть кнопка "вывести деньги". По клику происходит ивент "onClick" и его обрабатывает контроллер. Контроллер просит модельку представляющую баланс провести операцию. То есть тут задача контроллера лишь сконвертировать асинхронное действие пользователя в синхронный вызов метода модели.


              Но дальше интереснее, потому что модель в этой схеме все еще относится к UI. Ее задача — отделить представление от приложения. Это эдакая точка входа, вершина графа объектов. Она же просит другой объект совершить операцию (делигирование ответственности), и когда та закончит спросит у еще одного объекта "а какой теперь у меня баланс?". Если баланс поменялся — кидаем событие, которое ловит вьюшка. По этому событию вьюшка обновляет циферку баланса.


              картинка.


              Собственно а теперь размышляем что у нас в WEB. Если мы будем рассматривать только бэкэнд, то у нас UI для приложения это http запросы и ответы. У нас нету "вьюшки" как таковой, точнее под вьюшкой мы разве что http можем понимать, эдакая пассивная вьюшка. "Контроллер" теперь выполняет роль конвертера http запросов в запросы к приложению. Причем на нашу операцию — вывод денег, мы отдадим не баланс а редирект на то место где можно этот баланс глянуть. application layer ничуть не поменялся, а вот ui layer теперь представлен только контроллерами.


              картинка.


              то можно из контроллера вызвать нужный метод сущности и все. :)

              в моем примере мы именно так и делаем для просмотра баланса. Поскольку тут все хорошо, мы просим какой-то объект (не хочу использовать термин сущность потому что может быть конфликт с другими терминами) предоставить нам информацию по балансу для определенного юзера. И все, далее мы заворачиваем это в http ответ и вуаля. Все четко и красиво.


              Но вот в случае с выводом денег нам все равно нужен объект который инкапсулирует в себе всю операцию. И этот объект не должен ничего знать о HTTP.


              То есть правило простое. Контроллеру на одно действие нужен один объект от приложения, который предоставит всю необходимую информацию для ответа за один вызов одного метода. Далее мы в контроллере уже будем заниматься формированием нужного нам представления, рендрить из этих данных html или json сериализовать, не важно.


              Если такого объекта не находится, есть только один вариант: сделать такой объект. Этим объектом иногда могут служить другие контроллеры (например мы рендрим страницу и нам нужна информация для нескольких блоков, HMVC и все такое).


              Что бы быть конкретнее по поводу "одного объекта и одного вызова метода этого объекта на действие контроллера", еще рассмотрим batch обработку. Когда нам может придти массив действий. Но хоть контроллер (и экшен контроллера если хотите) у нас один, действий много. А потому в этом случае просто на каждое действие ровно один вызов метода приложения.


              tl;dr все на самом деле сводится лишь к тому что бы у нас направление зависимостей были в нужную сторону, от менее стабильного (то что чаще меняется) к более стабильному (то что меняется реже).


              1. http2
                01.06.2017 13:55
                -1

                Я полностью с Вами согласен. :)
                Просто иногда (часто) надобности в модели нет.
                Сначала удобно набросать в контроллере. А потом по мере развития можно и вынести это в модель, когда будет понимание, что там должно быть.


                1. Fesor
                  01.06.2017 14:20

                  Просто иногда (часто) надобности в модели нет.

                  вы ничего не поняли из того что я написал, да?


                  Сначала удобно набросать в контроллере. А потом по мере развития можно и вынести это в модель, когда будет понимание, что там должно быть.

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


                  • юнит тесты для слабаков,
                  • TDD/ATDD придумали трусы
                  • BDD никогда не надо


                  1. http2
                    01.06.2017 15:10
                    -1

                    юнит тесты для слабаков,

                    О тестах

                    Это я пишу о личных проектах.
                    На работе по другому чуток. :)
                    Вы стремитесь к 100%-ому покрытию?


                    1. Fesor
                      01.06.2017 16:42

                      Вы стремитесь к 100%-ому покрытию?

                      ключевое слово — стемиться. 100% покрытие тестами невозможно (ну только если у вас все очень просто). Вопрос здравого смысла.


                      Что до вашей статьи...


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

                      самый ужасный вывод который можно сделать...


                      1. http2
                        01.06.2017 20:05

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

                        А-ха-ха.
                        А разве не так? :)


                        1. Fesor
                          01.06.2017 20:24

                          Рекомендую к просмотру. Лучшее видео на эту тему.



                          1. http2
                            01.06.2017 22:36

                            Боюсь, я на английском не осилю.
                            На бусурманском обычно льют воду ни о чем, говорят о тривиальных вещах, будто это какое-то открытие. :)
                            На выходных попробую. :)

                            П.С.
                            Постоянные читатели статьи.
                            Разве она со времени появления 2 года назад не улучшилась?


                            1. Fesor
                              01.06.2017 22:41

                              На бусурманском обычно льют воду ни о чем, говорят о тривиальных вещах,

                              тут все по делу.


    1. iqw
      01.06.2017 10:53
      +1

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

      Особенного внимания заслуживает цитата:

      Зачем извращаться и писать запрос на php, если можно просто взять и написать? Абы було?

      Если возникает такой вопрос — то тут явно к психиатру, а не на хабр.


      1. http2
        01.06.2017 12:54
        -2

        Господи, если ты пишешь проект сам — флаг тебе в руки, хоть там сферического коня в вакууме сочиняй

        Господи, если вы пишете проект на фреймворке — флаг вам в руки, хоть там сфе…

        Если возникает такой вопрос — то тут явно к психиатру, а не на хабр.

        Ты тоже думаешь, что я пропагандирую писать запросы, как в комменте оратора ниже ( MetaDone )? :)
        Может вам к психиатру? :)

        Ищите комменты от «M-A-XG» в той теме. :)


    1. MetaDone
      01.06.2017 10:59

      Зачем извращаться и писать запрос на php, если можно просто взять и написать? Абы було?

      Хороший пример показан здесь


  1. scronheim
    31.05.2017 08:12

    как то подозрительно Laravel проиграл во всех категориях


  1. Rathil
    31.05.2017 08:55

    Мы сейчас тоже выбрали фалкон + реакт. Пока устраивает. От самих фреймворков используется минимум, все остальное пишется по необходимости, которой достаточно… До этого проект был на yii1.


  1. Knase
    31.05.2017 12:30

    yii 1.12 забыли, а на нем много чего уже написано))))


  1. Dimash2
    31.05.2017 12:30

    Когда я писал о том, что выбираю Phalcon из-за его производительсноти — меня минусовали, это ведь не 10%, это значительная разница.


    1. MetaDone
      31.05.2017 12:49
      +1

      добавьте туда пакет vlucas/phpdotenv, настройте и производительность резко просядет. В принципе любой сторонний пакет резко бьет по производительности phalcon
      лично по моим наблюдениям его круто применять в тех местах, где все можно реализовать только его средствами, например в апишках — тогда профит будет ощутимым


      1. Dimash2
        31.05.2017 13:31

        У меня подход следующий:

        — Фронт, если это не js, а шаблонизатор на php, то это чистый phalcon с volt и моя библиотека CURL запросов. Делает он API запросы которые кеширует

        — API на Phalcon имеет пару хелперов по работе с базой, ну и есть крупные библиотеки по работе с EXCEL ид но они запускаются только по необходимости опреленными скриптиами.

        Так что все вроде справедливо


  1. misantron
    31.05.2017 12:30
    +1

    Не совсем понятно почему для тестов был выбран Silex версии 1.3, хотя уже год как вышел 2.0


  1. sspat
    05.06.2017 00:25
    +1

    В чем вообще смысл измерения производительности фреймворка, когда в реальном приложении 95% времени генерации страницы зависит от того что происходит на инфраструктурном уровне и уровне бизнес логики, на которые фреймворк вообще не влияет никак? Это все равно что сравнивать скорость двух автомобилей скатывая с горки голое шасси от них, а безопасность измерять роняя один двигатель на другой.

    Если фрейморк отдает голый хеллоу ворлд на десять миллисекунд дольше и загружает при этом на сотню файлов больше, говорит не о том, что он хуже, как раз наоборот он может оказаться лучше. предоставляя больше качественных абстракций для работы с низкоуровневыми вещами и готовых инструментов. Поэтому я бы все графики перевернул вверх ногами, тогда все фреймворки (кроме phalcon, его в силу реализации вообще неуместно сравнивать с остальными) окажутся как раз на своих местах — CI со второго места провалится в зад, где ему самое место в 2017 году.


    1. Dimash2
      05.06.2017 14:40
      -1

      Умножайте на количество, 1000 *10 = 10 000ms


      1. sspat
        05.06.2017 15:19
        +1

        Количество чего? Запросов? От этого соотношение времени которое уходит на выполнение кода ядра фреймворка к времени выполнения остальнього кода не изменится. На тех масштабах, где играет роль 10 мс разницы времени генерации страницы между двумя фреймворками уже нет этих фреймворков, там остается голый php с выносом большей части инфраструктурного кода вообще на другие языки программирования. Вы не тем себе и другим голову забиваете. Интернет заполнен статьями подобными этой, где сравниваются хеллоу ворлды в вакууме, при этом единицы пишут полезные обзоры, где сравниваются реально значимые показатели фреймворков, такие как скорость разработки и простота поддержки, активность коммьюнити, база готовых наработок и интеграций и т.д.


      1. Fesor
        05.06.2017 18:27

        Логика на уровне "Инфляция всего 2%! Умножь на 1000 и грусти".


        В вашем умножении нет смысла. Вот если бы у вас был класстер из 200 серваков, и разница по стоимости железа на 10% была бы соизмерима с окладом разработчика в месяц, тогда об этих 10ms можно уже заморачиваться. И то далеко не факт что это будет одним из первых пунктов в плане приоритетов.


        Но тут важный момент — когда вам надо 200 серваков, вы уже состоявшийся продукт. И тут уже есть возможность потратить недельку на то что бы "вот тот жирный компонент фреймворка заменить узкоспециализированным под нашу инфраструктуру".


        И преимущество фреймворков типа symfony в том что они как раз таки позволяют это сделать относительно безболезненно. Надо заменить роутер на что-то побыстрее в контексте наших задач — вуаля. Надо ускорить запросы на чтение — ставим мидлварю которая будет ранать наш http kernel в cli режиме без необходимости бутстрапить приложение полностью.


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


        Тут аналогия с ORM. Можно юзать их, полагаться на лэйзи подгрузку данных, а когда спустя месяц-два запросы стабилизируются — оптимизировать с использованием явных джойнов и минуя дорогой этап гидрации. А быть может у нас из 200 серваков 20 это реплики базы данных, что бы запросы не вешали систему, и тогда 180 серваков с PHP уже явно не будут самым значительной статьей расходов как с экономической точки зрения так и с точки зрения производительности.


        tl;dr идея в том что бы обменять производительность на гибкость и скорость разработки и при увеличении стабильности модуля уже загоняться по оптимизациям если в этом есть существенный профит с экономической точки зрения.