Новое в Symfony 4.1: Самый Быстрый PHP Маршрутизатор

Symfony 4 - быстрейший PHP Framework (по мнению независимых и не предвзятых тестов), но мы продолжаем работать над его улучшением. В Symfony 4.1 мы улучшили Routing компонент, чтобы сделать его еще быстрее при обработке URL.

В web приложениях, маршрутизация разделена на две основные операции: 

  • Генерация - генерирует URL для заданного маршрута и параметров
  • Сопоставление - определение какой PHP код (например какой контроллер) должен выполнится для заданного URL.

Чтобы ускорить данные операции, Symfony "компилирует" все маршруты в уже оптимизированном виде в один PHP класс. Код ниже - это пример такого класса, сгенерированный для стандартного Symfony Demo Application:

// var/cache/prod/srcProdDebugProjectContainerUrlMatcher.php
class srcProdDebugProjectContainerUrlMatcher
{
  // ...

  public function match($rawPathinfo)
  {
    // ...

    // blog_post
    if (preg_match('#^/(?P<_locale>en|fr|de|es)/blog/posts/(?P<slug>[^/]++)$#s', $pathinfo, $matches)) {
      if ('GET' !== $canonicalMethod) {
        $allow[] = 'GET';
        goto not_blog_post;
      }

      return $this->mergeDefaults(array_replace($matches, array('_route' => 'blog_post')), array ( '_controller' => 'App\\Controller\\BlogController::postShow', '_locale' => 'en',));
    }
    not_blog_post:

    // ...
  }
}

В Symfony 4.1, на основе идей из этой статьи, был переписан генератор для этого класса. В статье объясняются техники использованные в FastRoute (Routing библиотеки написанной гениальным PHP контрибьютором Никитой Поповым.

Основной идеей является то, что мы отказываемся от вызова preg_match для каждого маршрута в отдельности, и объеденяем все наши регулярные выражение в одно большое регулярное выражение. И теперь, после этих изменений, класс с маршрутами для Symfony Demo Application будет выглядеть следующим образом:

$regexList = array(
  0 => '{^(?'
      .'|/(en|fr|de|es)/admin/post/?(*:82)'
      .'|/(en|fr|de|es)/admin/post/new(*:166)'
      .'|/(en|fr|de|es)/admin/post/(\\d+)(*:253)'
      .'|/(en|fr|de|es)/admin/post/(\\d+)/edit(*:345)'
      .'|/(en|fr|de|es)/admin/post/([^/]++)/delete(*:442)'
      .'|/(en|fr|de|es)/blog/?(*:519)'
      .'|/(en|fr|de|es)/blog/rss\\.xml(*:603)'
      .'|/(en|fr|de|es)/blog/page/([1-9]\\d*)(*:694)'
      .'|/(en|fr|de|es)/blog/posts/([^/]++)(*:784)'
      .'|/(en|fr|de|es)/blog/comment/([^/]++)/new(*:880)'
      .'|/(en|fr|de|es)/blog/search(*:962)'
      .'|/(en|fr|de|es)/login(*:1038)'
      .'|/(en|fr|de|es)/logout(*:1116)'
      .'|/(en|fr|de|es)?(*:1188)'
    .')$}sD',
);

foreach ($regexList as $offset => $regex) {
  // ...

  default:
    $routes = array(
      // ...
      784 => array(array('_route' => 'blog_post', '_controller' => 'App\\Controller\\BlogController::postShow', '_locale' => 'en'), array('_locale', 'slug'), array('GET' => 0), null),
    );

  // ...
}

На практике, объединение всех регулярных выражений в одно, повышает эффективность сопоставления URL-адресов почти на два порядка. В наших синтетических тестах, сопоставление URL в Symfony 4.1 в 77 раз быстрее чем в предыдущих версиях Symfony. Это так же означает, что маршрутизатор в Symfony 4.1 является самым быстрым PHP маршрутизатором.

Опубликовано:

Категории: Новости