Nuevo en Symfony 4.1: el router más rápido de PHP

Symfony 4 es el framework PHP más rápido según algunos benchmarks independientes, pero aún así seguimos trabajando sin descanso para mejorar su rendimiento. En Symfony 4.1, hemos mejorado el componente Routing para que procese las URL entrantes mucho más rápido.

En las aplicaciones web, el routing se divide en dos tareas principales: 1) generar una URL a partir de una ruta y parámetros dados (generation en inglés) y 2) procesar las URL entrantes para decidir qué código PHP (normalmente un controlador) se ejecuta como respuesta (matching en inglés).

Para mejorar el rendimiento de las aplicaciones, durante la fase de compilación Symfony genera una clase PHP llamada matcher que contiene la definición de todas las rutas de la aplicación y está optimizado para hacer el matching lo más rápido posible. Por ejemplo, este es un trozo del archivo generado para la aplicación Symfony Demo:

// 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:
 
        // ...
    }
}

En Symfony 4.1 hemos refactorizado el generador de este matcher basándonos en las ideas presentadas en este artículo: Fast request routing using regular expressions. El artículo explica la técnica que usa FastRoute, una librería creada por el genio Nikita Popov, contribuidor del core de PHP.

La idea básica es que en vez de hacer una llamada a preg_match() por cada ruta que quieres comprobar, es mejor combinar las expresiones regulares de todas las rutas en una única expresión regular gigantesca y hacer un solo preg_match(). Además de esta, hicimos muchas otras optimizaciones. Si tienes cuirosidad, tienes todos los detalles en los pull requests #26059 y #26169.

Con todo ello, utilizando el mismo ejemplo que antes, este es el nuevo código que se genera para hacer el matching de la ruta blog_post:

$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),
        );
 
    // ...
}

En la práctica, combinar todas las expresiones regulares mejora el rendimiento casi dos órdenes de magnitud. En nuestros benchmarks, el router de Symfony 4.1 es 77 veces más rápido que en las anteriores versiones de Symfony. De hecho, el router de Symfony 4.1 es el más rápido de PHP, superando a FastRoute y todas las demás librerías similares.

Lo mejor de todo es que no tienes que hacer ningún cambio en tu aplicación para disfrutar de este router super rápido. Solamente tendrás que actualizar a Symfony 4.1 cuando se publique a finales de mayo de 2018. Mientras tanto, puedes probarlo en tus aplicaciones y reportar cualquier error que te encuentres.

Esta funcionalidad fue contribuida por Nicolas Grekas en los pull requests #26059 y #26169.


Actualización: Nicolas ha publicado dos artículos técnicos con todos los detalles sobre cómo funciona el nuevo router:

Fuente: New in Symfony 4.1: Fastest PHP Router

Comentarios

Publicada el

16 de febrero de 2018

Etiquetas

Proyectos Symfony destacados

La plataforma de eCommerce 100% Symfony que rivaliza con Magento y PrestaShop. Ver más

Síguenos en @symfony_es para acceder a las últimas noticias.