Elevate Your Code: Mastering Refactoring in Symfony with RectorPHP

Jakub Skowron (skowron.dev)
4 min readSep 4, 2023

--

Photo by AbsolutVision on Unsplash

In the ever-evolving landscape of software development, staying updated with the latest best practices and tools is not just a luxury — it’s a necessity. As PHP continues to mature and frameworks like Symfony introduce new features and paradigms, developers are often left with the daunting task of refactoring legacy code. But what if there was a tool that could simplify this process, making code upgrades almost seamless? Enter RectorPHP, a game-changer in the world of PHP refactoring. In this article, we’ll dive deep into the capabilities of RectorPHP, especially in the context of Symfony, and explore how it can elevate your codebase to modern standards. Whether you’re a seasoned Symfony developer or just getting started, this guide promises insights that can streamline your development workflow. So, let’s embark on this journey of code transformation!

What is RectorPHP?

RectorPHP is a CLI tool for PHP that automates the code refactoring process. It is based on Symfony components and allows for instant updates and architectural refactoring.

Installing RectorPHP in a project: To install RectorPHP in a project, simply use the command:

composer require rector/rector --dev

Configuration options: RectorPHP uses the rector.php file for configuration. In it, you can define sets of rules that are to be applied during refactoring.

Predefined settings sets: RectorPHP offers many predefined rule sets that can be imported into your configuration file. For Symfony, sets such as SYMFONY_33, SYMFONY_40, etc. are available, which automatically adjust the code to the appropriate version of the framework.

Settings for Symfony: If you want to update your Symfony project to a newer version, you can use the ready-made rule sets. For example, to update the project to Symfony 5.0, you can add the following code to the rector.php file:

use Rector\Symfony\Set\SymfonySetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->import(SymfonySetList::SYMFONY_50);
};

Main challenges in refactoring PHP and Symfony code

Refactoring code in PHP and Symfony is not just about improving code quality, but also about adapting to new versions of the framework, libraries, and components. Challenges include:

  1. Updates between versions: Symfony, like many other frameworks, regularly introduces new versions that may contain incompatible changes. Updating the code to a newer version can be tedious and risky.
  2. Outdated practices: As technologies evolve, certain practices become outdated. For example, earlier versions of Symfony relied on a YAML-based approach, while newer versions promote PHP configuration.
  3. Integration with other libraries: Many developers use additional libraries, such as Doctrine, which also update regularly. Refactoring code to be compatible with the latest versions of these libraries can be challenging.

Example use case: Refactoring with RectorPHP

  • Case 1: Refactoring code related to dependency injection in Symfony.

Old code:

class LoggingEventSubscriber implements EventSubscriberInterface {
public function setController($controller) {
$this->logger = $this->get('logger');
$this->logger->log('Event registered!');
}
}

New code after refactoring:

class LoggingEventSubscriber implements EventSubscriberInterface {

private $logger;

public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}

public function handleEvent() {
$this->logger->log('Event registered!');
}
}
  • Case 2: Working with Doctrine — If you have Doctrine entities with outdated annotations or want to transform old DQL queries into newer ones, RectorPHP can help automate this process.

Old code:

/**
* @Entity
* @Table(name="users")
*/
class User {
/**
* @Id
* @GeneratedValue
* @Column(type="integer")
*/
private $id;
}

New code after refactoring:

#[Entity]
#[Table(name: 'users')]
class User {
#[Id, GeneratedValue, Column(type: 'integer')]
private $id;
}
  • Case 3: Generating Symfony entities from old code — If you have old code that does not use Symfony entities, RectorPHP can help automatically generate appropriate entities based on that code.

Old code:

class User {
/** @var string */
private $name;
/** @var string */
private $email;

public function setName($name) {
$this->name = $name;
}

public function setEmail($email) {
$this->email = $email;
}
}

New code after refactoring:

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
* @ORM\Table(name="users")
*/
class User {
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;

/**
* @ORM\Column(type="string", length=100)
*/
private $name;

/**
* @ORM\Column(type="string", length=100)
*/
private $email;


public function getId(): int
{
return $this->id;
}

public function setId(int $id): self
{
$this->id = $id;
return $this;
}

public function getName(): string
{
return $this->name;
}

public function setName(string $name): self
{
$this->name = $name;
return $this;
}

public function getEmail(): string
{
return $this->email;
}

public function setEmail(int $email): self
{
$this->email = $email;
return $this;
}

// ... rest of the code
}

Daily use of RectorPHP

Integration with IDE:

  • PHPStorm: You can configure PHPStorm to use RectorPHP as a code inspection tool. Just add RectorPHP as an external tool and configure the appropriate paths.
  • Visual Studio Code: There is a RectorPHP extension for VS Code that can be installed from the marketplace. After installation, you can run RectorPHP directly from the editor.

Tools cooperating with RectorPHP:

  • PHPStan: Static code analysis that helps detect errors in the code without running it.
  • Psalm: Similar to PHPStan, but with a slightly different approach and rule set.

Installation and configuration: To install the above tools and configure them to work with RectorPHP, you can use the following commands:

composer require --dev phpstan/phpstan
composer require --dev vimeo/psalm

Then you can configure each tool according to its documentation to ensure the best code quality.

RectorPHP in the CI/CD approach

To integrate RectorPHP with the CI/CD process, you can add appropriate steps to your pipeline. Here is an example code for Bitbucket Pipelines:

pipelines:
default:
- step:
name: RectorPHP Refactoring
script:
- composer install
- vendor/bin/rector process

Conclusion

RectorPHP is an indispensable tool for PHP and Symfony developers. It allows for automatic code refactoring, assisting in updates, architectural corrections, and integration with other libraries. With integration with tools such as PHPStan, Psalm, and IDEs, RectorPHP becomes even more powerful, ensuring the highest code quality.

--

--

Jakub Skowron (skowron.dev)

Poland based PHP/Python Web Backend dev. Love to work with Symfony and FastAPI frameworks. In spare time totally gearhead.