Symfony всегда можно было использовать в качестве микрофреймворка. Среди других микрофреймворков, которые позволяют вам добавлять в них все, что пожелаете, можно выделить Empty Edition и MicroFrameworkBundle.
Существует множество критериев, за счет которых фреймворк классификацируется как «микрофреймворк». Вот некоторые из них:
- небольшой API (использование кода фреймворка в вашем приложении)
- мало строк кода (LOC)
- мало зависимостей (количество используемых сторонних библиотек)
- небольшой объем (время загрузки фреймворка)
Можно ли считать Symfony микрофреймворком? Давайте разберемся.
Примечание: О том, как определить, является ли фреймворк микрофреймворком, почитайте статью Игоря Видлера (Igor Wiedler) Насколько тяжел Silex?
Измерение
Несмотря на то, что примеры типа «Hello World» редко отражают приложения, используемые в реальной жизни, они подойдут для цели этой статьи, а именно: измерить API, строки кода, зависимости и объем Symfony.
Поскольку зависимости и объем измерить легко, мы будем полагаться на эти параметры. Но все эталонные тесты определяются компьютером, на котором они проводятся, поэтому нам понадобится ориентир: простое PHP-приложение Hello World:
<?php
// index.php
echo 'Hello World';
Давайте проведем эталонный тест:
php -S localhost:2501 &
ab -c 10 -t 10 'http://localhost:2501/index.php'
killall php
Результат: 6 915.03 запросов в секунду.
Стандартная версия (Standard Edition)
Чтобы получить Стандартную версию, мы можем использовать composer
:
composer create-project symfony/framework-standard-edition
cd framework-standard-edition
Поскольку стандартная версия основывается на концепции «применяй готовые решения для 80% вариантов использования», она практически готова, нам нужно лишь немного настроить наш контроллер:
<?php
// src/AppBundle/Controller/DefaultController.php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
/**
* @Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
return new Response('Hello World');
}
}
Проведем эталонный тест:
SYMFONY_ENV=prod composer update -o --no-dev
php -S localhost:2502 -t web &
ab -c 10 -t 10 'http://localhost:2502/app.php'
killall php
Результат: 134.23 запросов в секунду. Также мы перечислим зависимости:
tree -d -L 2 vendor/ | grep ' ' | wc -l
tree -d -L 2 vendor/ | grep ' ' | wc -l
Получаем 28 + 1, в которой мы вместо symfony должны указать все пакеты, которые она заменяет (44): 72. Подытожим:
- API: добавление нового маршрута в 1 шаг
- объем: в 52 раза медленнее, чем простое PHP-приложение
- размер: 72 зависимости
Пустая версия (Empty Edition)
Как было сказано выше, Cтандартная версия основывается на концепции «применяй готовые решения для 80% вариантов использования», поэтому она содержит много зависимостей, а это нам не подходит. Микрофреймворк обычно основывается на концепции «добавь все, что тебе нужно», и пустая версия как раз соответствует этой концепции.
Давайте посмотрим, сможем ли мы приблизить фреймворк к статусу «микро»:
composer create-project gnugat/symfony-empty-edition
cd symfony-empty-edition
Сначала создаем контроллер:
<?php
// src/AppBundle/Controller/HelloController.php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class HelloController
{
public function world(Request $request)
{
return new Response('Hello World');
}
}
Затем регистрируем его в качестве службы:
# app/config/services/controller.yml
services:
app.hello_controller:
class: AppBundle\Controller\HelloController
И наконец, регистрируем маршрут:
# app/config/routings/app.yml
hello_world:
path: /
defaults:
_controller: app.hello_controller:world
methods:
- GET
Проведем эталонный тест:
composer update -o --no-dev
php -S localhost:2503 -t web &
ab -c 10 -t 10 'http://localhost:2503/app.php'
killall php
Результат: 524.53 запросов в секунду. Перечислим зависимости:
tree -d -L 2 vendor/ | grep ' ' | wc -l
tree -d -L 2 vendor/ | grep ' ' | wc -l
Получаем 6 + 23 = 29.
В итоге:
- API: добавление нового маршрута в 3 шага
- объем: в 13 раз медленнее, чем простое PHP-приложение
- размер: 29 зависимости
Micro Framework Bundle
Уменьшив число зависимостей, мы значительно сократили объем фреймворка. Это неудивительно, поскольку:
- мы сократили число автозагружаемых классов
- мы сократили настраиваемую конфигурацию (параметры и определение службы)
- мы сократили время загрузки Контейнера внедрения зависимостей (меньше служб, которые необходимо инстанцировать)
- мы сократили число вызываемых слушателей событий
Можем сделать больше? Конечно: FrameworkBundle также основывается на концепции «применяй готовые решения для 80% вариантов использования» (включает Формы, Безопасность, Разработку шаблонов, Перевод, Ресурсы, аннотации и т.д).
Используя MicroFrameworkBundle, который предлагает строго ограниченный минимум и основывается на концепции «добавляй все, что тебе нужно», мы можем еще больше сократить число зависимостей. Итак, gnugat/micro-framework-bundle:
composer require 'gnugat/micro-framework-bundle'
composer remove 'symfony/framework-bundle'
Затем нам нужно заменить зарегистрировать бандл:
<?php
// app/AppKernel.php
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
class AppKernel extends Kernel
{
public function registerBundles()
{
return array(
new Gnugat\MicroFrameworkBundle\GnugatMicroFrameworkBundle(),
new AppBundle\AppBundle(),
);
}
public function getRootDir()
{
return __DIR__;
}
public function getCacheDir()
{
return dirname(__DIR__).'/var/cache/'.$this->environment;
}
public function getLogDir()
{
return dirname(__DIR__).'/var/logs';
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->rootDir.'/config/config_'.$this->environment.'.yml');
}
}
Наконец, мы можем избавиться от части конфигурации:
# app/config/config.yml
imports:
- { resource: parameters.yml }
- { resource: services/ }
Проведем эталонный тест для нашего урезанного приложения:
rm -rf var/*
composer update -o --no-dev
php -S localhost:2504 -t web &
ab -c 10 -t 10 'http://localhost:2504/app.php'
killall php
Результат: 872.83 запроса в секунду. Перечислим зависимости:
tree -d -L 2 vendor/ | grep ' ' | wc -l
tree -d -L 2 vendor/ | grep ' ' | wc -l
Получаем 3 + 13 = 16.
В итоге:
- API: добавление нового маршрута в 3 шага
- объем: в 8 раз медленне, чем простое PHP-приложение
- размер: 13 зависимостей.
Заключение
Symfony всегда можно было использовать в качестве бандла микрофреймворка. Основываясь на концепции «применяй готовые решения для 80% вариантов использования», Стандартная версия Standard Edition и FrameworkBundle предпочтительнее для начинающих.
А подходящей альтернативой для опытных разработчиков, которые ищут концепцию «добавляй все, что тебе нужно» (именно на этой концепции основывается большинство микрофреймворков), может стать использование Пустой версии (Empty Edition) и MicroFrameworkBundle (в них меньше зависимостей и они работают быстрее).