Olvídate del código obsoleto con Rector

Rector Banner.jpg
Solucionex
20
Ene 22

Uno de los problemas que tiene el código es que se queda obsoleto muy rápido debido que las tecnologías en las que se basan continúan avanzando, mientras que nuestro código se queda igual. Esto ocasiona que con el paso del tiempo aparezcan tanto nuevas características como vulnerabilidades de seguridad. Puede llegar un punto en el que a la hora de dar el salto de una versión a otra el código que teníamos no sea compatible con las nuevas versiones, por lo que nos tocaría adaptarlo para cumplir los requisitos.

A su vez, esto genera más problemas tanto de inversión de tiempo como posibles nuevos fallos. La comunidad de Rector se dió cuenta del gran problema que esto originaba y se pusieron manos a la obra para aportar una solución.

 

🤔 ¿Qué es Rector?

Es una herramienta que permite actualizar código con soporte desde PHP 5.3 hasta 8.1 en unos instantes y con una sintaxis clara y concisa. Se compone de más de 500 reglas que podemos aplicar para dejar nuestro código a la última y con buenas prácticas. Proyectos como Drupal lo utilizan para ayudarse a relizar grandes cambios en su código fuente y mantener actulizados los módulos de la comunidad aunque éstos ya no tengan soporte. El proceso es semi-automático, en el archivo rector.php indicamos las reglas que queremos aplicar y lanzamos el comando vendor/bin/rector process [TARGET].

 

⚙️ Instalación y configuración

La instalación es bastante sencilla y rápida, nos apoyamos en el gestor de dependencias Composer para ello.

composer require rector/rector --dev

A partir de aquí lo único que hay que hacer es inicializar la configuración:

vendor/bin/rector init

Esto crea un archivo rector.php en la raíz del proyecto en el que indicaremos las reglas a usar.

 

💻 Caso de uso

En mi situación tengo un Symfony 5.3 que quiero actualizar a Symfony 5.4 y además a PHP 8.0 desde 7.4 usando atributos en lugar de anotaciones. En un escenario normal terndríamos que sustituir a mano cada una de las anotaciones de Doctrine en las entidades por atributos de PHP y revisar el código que se queda obsoleto de 5.3 a 5.4. Con rector tenemos varias reglas para realizar lo mismo de forma automática.

  • Revisa el código en busca de incompatibilidades con PHP 8.0 y las corrige
    • LevelSetList::UP_TO_PHP_80
  • Revisan el código para sustituir anotaciones por atributos
    • DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES
    • SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES
    • NetteSetList::ANNOTATIONS_TO_ATTRIBUTES
  • Revisan el código obsoleto y lo sustituye por uno compatible con la versión de Symfony
    • SymfonySetList::SYMFONY_54
  • Revisan el código y aplican buenas prácticas tanto de calidad como estilo del código
    • SetList::CODING_STYLE
    • SetList::CODE_QUALITY

Dependiendo del proyecto aplicaremos unas reglas u otras según las necesidades. El archivo final en base a esta configuración sería este:

<?php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Rector\Doctrine\Set\DoctrineSetList;
use Rector\Nette\Set\NetteSetList;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
use Rector\Symfony\Set\SensiolabsSetList;
use Rector\Symfony\Set\SymfonySetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    // get parameters
    $parameters = $containerConfigurator->parameters();
    $parameters->set(Option::PATHS, [
        __DIR__.'/src',
    ]);

    // Define what rule sets will be applied
    $containerConfigurator->import(LevelSetList::UP_TO_PHP_80);
    $containerConfigurator->import(DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES);
    $containerConfigurator->import(SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES);
    $containerConfigurator->import(NetteSetList::ANNOTATIONS_TO_ATTRIBUTES);
    $containerConfigurator->import(SensiolabsSetList::FRAMEWORK_EXTRA_61);
    $containerConfigurator->import(SetList::CODING_STYLE);
    $containerConfigurator->import(SetList::CODE_QUALITY);
    $containerConfigurator->import(SymfonySetList::SYMFONY_54);

};

En mi caso estoy aplicando conjuntos de reglas, esto simplifica mucho ya que incluyen todas las reglas necesarias para que eso se cumpla. Si sólo nos interesa alguna regla en concreto podemos usarla de esta manera:

<?php

declare(strict_types=1);

use Rector\Php74\Rector\Property\TypedPropertyRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {

    // get services (needed for register a single rule)
     $services = $containerConfigurator->services();

    // register a single rule
     $services->set(TypedPropertyRector::class);
};

Una vez tengamos esto lanzamos esto (en mi caso es src ya que es el directorio donde reside mi código) y él solito se encargará de todo.

vendor/bin/rector process src

Con esto ya podríamos dar el salto a PHP 8.0 y Symfony 5.4 y lo mejor de todo, en un par de minutos por lo que disponemos de más tiempo para seguir creando.

 

💡 Recomendaciones personales

Es fácil perderse entre tantas reglas por lo que voy a dejar aquí algunas de las que más me gustan a mí.

  • TypedPropertyRector: con la llegada de PHP 7.4 se ha popularizado el uso de propiedades tipadas por lo que éste nos ayuda a añadir tipado a las propiedades que no lo tengan.
  • EarlyReturn: Hay bastantes en esta categoría, aquí algunos de ellos. Los nombres son bastante descriptivos, pero básicamente aplica el patrón early return allí dónde se pueda
    • ChangeAndIfToEarlyReturnRector
    • ChangeIfElseValueAssignToEarlyReturnRector
    • ChangeNestedForeachIfsToEarlyContinueRector
    • ChangeNestedIfsToEarlyReturnRector
    • PreparedValueToEarlyReturnRector
  • SeparateMultiUseImportsRector: Separa los import en líneas independientes.
  • ArrayThisCallToThisMethodCallRector: Sustituye los callbacks en array por una llamada al método

Podría poner aquí la biblia pero como cada persona tiene sus preferencias personales os recomiendo visitar su repositorio en github y elegir en base a lo que cada uno necesite.

 

Conclusiones

Opino que Rector es una herramienta muy útil ya que ahorra mucho tiempo y permite revivir proyectos desfasados con poca inversión. Esto no significa que el 100% lo vaya a hacer Rector pero sí que supone una gran ayuda a la hora de mantener al día todos esos proyectos que con el tiempo se van quedando desfasados.

 

Nada más que contar, ¡nos vemos en el próximo post!