<!--
  canonical-url: https://www.avonture.be/blog/php-rector
  published:     2024-02-14
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Rector 1.0.0 🎉🎉🎉, my friend, my coach

> Meet PHP Rector, the free, powerful tool for automatic PHP codebase upgrades and refactoring. Instantly improve code quality and become a better PHP developer.

---
![Rector 1.0.0 🎉🎉🎉, my friend, my coach](/img/v2/rector.webp)

**TL;DR**

This article introduces Rector, a free tool that scans PHP code and suggests (or automatically applies) modernization and refactoring improvements. Using a simple `sayHello` function as an example, it shows Rector simplifying an `if/else` into a ternary expression, removing a useless variable, and adding proper type hints and a return type — all via `vendor/bin/rector process --dry-run --config rector.php`.

If there was only one, it would be [Rector](https://github.com/rectorphp/rector). **Rector is extremely powerful and brilliant and, you know what, it's free!**

Rector is a tremendous application to scan and automatically upgrade your codebase to a given version of PHP and this means, too, to inspect how you're coding.

Rector will look at every line of code, every loop, every conditional test, every function, every class in a PHP source code and suggest improvements.

In this role, it will not only detect improvements to my code (like a static analysis tool) but, and this is the biggest advantage for me, it will show me how I can become a better developer.

I REALLY LOVE RECTOR 💕

Like a lot of people, I learned PHP on my own and that was at the time of PHP 5. Like a lot of people, I certainly picked up some bad habits and because it's impossible to keep up with every evolution of the language, my skills don't increase at the same time as the language.

So, perhaps, I'm still using *old-fashioned* syntax like doing a simple `if ... then ... else` when in fact it's not useful. Maybe I'm going to use a variable to store a value when it's absolutely useless.

Let's take a look at a very simple example (`sayHello.php`):

**sayHello.php**

```php
<?php

function sayHello($firstname = '')
{
    if ($firstname == '') {
        $text = 'Hello World!';
    } else {
        $text = 'Hello ' . $firstname;
    }

    return $text;
}

echo sayHello('Christophe');
```

Simple and effective, isn't it? And, above all, the code is perfectly functional and well written, respecting all the layout conventions.

> **I'm an excellent developer. Thank you and goodbye.:**
>
> Well, in fact, **I was an excellent developer** but I stopped being one ten years ago.

What's wrong with my code?

* `$firstname` is a string no? So why not write `string $firstname`?,
* since PHP 7.x, there is a thing called `ternary operator`; you didn't know that?,
* Using the `ternary operator`; the `$text` variable becomes useless and
* the function is returning a string (the `$text` variable) but the prototype of the function didn't mention this. So why not write `function sayHello($firstname = ''): string`

## Here is what Rector says about it

Before you install anything, here is the answer Rector gives on that exact file:

![Rector is simplifying our sayHello function](./images/rector_say_hello.webp)

A colored diff — the code as it is, the code as it could be — and, at the bottom of the screen, an `Applied rules:` section.

## Why it works

* **Rector reasons in named rules, not in patterns.** Every change comes with the name of the rule that produced it, and that name is a link to a documented explanation.
* **It parses your code, it doesn't grep it.** Rector builds the syntax tree of the file, which is why it can tell that a variable is only there to be returned, or that a return value can only ever be a string.
* **Nothing moves until you say so.** With `--dry-run` you get the diff and your files stay exactly as they were, so reading the suggestions costs nothing.

## Install Rector

> **You can try Rector without installing it:**
>
> Rector is one of the tools shipped in the [jakzal/phpqa](/blog/php-jakzal-phpqa) Docker image and it comes preinstalled in the [PHP devcontainer](/blog/php-devcontainer). If you just want to see what it says about your code, start there.

When you use composer to manage dependencies in your project, just run `composer require rector/rector --dev` in a console. This will install Rector as a dev-dependency (which is pretty good).

The next thing is to create a configuration file. You can use a standard one (to do this just run `vendor/bin/rector` and the file will be created) or create yours.

I suggest creating a `rector.php` file in your project with this content:

**rector.php**

```php
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withSkip(
        [
            '.git', 'node_modules','vendor'
        ]
    )
    ->withPhpSets(php82: true)
    ->withPreparedSets(codeQuality: true, deadCode: true, typeDeclarations: true);
```

For simplicity, create the `rector.php` file in your project's root directory.

## Run Rector

The command that produced the screenshot above is `vendor/bin/rector process sayHello.php --dry-run --config rector.php`.

Let's take a look at it:

* `vendor/bin/rector`: this is the executable to start,
* `process`: the action to run, it's always `process`,
* `sayHello.php`: the file to scan. You can type `.` for your entire project or f.i. `app` when `app` is a folder,
* `--dry-run`: ask Rector to, only, show suggestions and not to update the file and
* `--config rector.php`: this is the name of our configuration file.

So running that command is just like asking: **please take a look at my sayHello.php script and show me how I can improve my syntax.** And Rector does it; quickly and without judgment, showing the changes it **could** make and explaining why it thinks they're better.

## Applied rules

Take a look at the `Applied rules:` section at the end of the screen capture; here are the rules with a link to their explanations:

* [SimplifyIfElseToTernaryRector](https://github.com/rectorphp/rector/blob/main/docs/rector_rules_overview.md#simplifyifelsetoternaryrector)
* [SimplifyUselessVariableRector](https://github.com/rectorphp/rector/blob/main/docs/rector_rules_overview.md#simplifyuselessvariablerector)
* [ReturnTypeFromStrictScalarReturnExprRector](https://github.com/rectorphp/rector/blob/main/docs/rector_rules_overview.md#returntypefromstrictscalarreturnexprrector)
* [StrictStringParamConcatRector](https://github.com/rectorphp/rector/blob/main/docs/rector_rules_overview.md#strictstringparamconcatrector)

### SimplifyIfElseToTernaryRector

Using the `ternary operator`, we can often replace a `if then else` structure with a one-line test; the `ternary operator`.

```diff
function sayHello($firstname = '')
{
-    if ($firstname == '') {
-        $text = 'Hello World';
-     } else {
-        $text = 'Hello ' . $firstname;
-     }
// highlight-next-line
+    $text = $firstname == '' ? 'Hello World' : 'Hello ' . $firstname;
     return $text;
}
```

### SimplifyUselessVariableRector

I think everyone will agree: storing the value in variable `$text` then returned the variable is useless and it's just pollution.

```diff
function sayHello($firstname = '')
-    $text = $firstname == '' ? 'Hello World' : 'Hello ' . $firstname;
-    return $text;
// highlight-next-line
+    return $firstname == '' ? 'Hello World' : 'Hello ' . $firstname;
};
```

### ReturnTypeFromStrictScalarReturnExprRector

When the return type can be derived (here, Rector understand we're returning a string) then the function prototype can be adapted in this way.

```diff
class SomeClass
{
-    public function sayHello($firstname = '')
// highlight-next-line
+    public function sayHello($firstname = ''): string
    {
        return $firstname == '' ? 'Hello World' : 'Hello ' . $firstname;
    }
}
```

### StrictStringParamConcatRector

When a parameter is a string but not type as a string, Rector see it and suggest updating the prototype as such:

```diff
class SomeClass
{
-    public function sayHello($firstname = ''): string
// highlight-next-line
+    public function sayHello(string $firstname = ''): string
    {
        return $firstname == '' ? 'Hello World' : 'Hello ' . $firstname;
    }
}
```

## Final code

So, back to our console, running `vendor/bin/rector process sayHello.php --dry-run --config rector.php` will show me, in the console, the new *refactored* version of my code:

**index.php**

```php
<?php

function sayHello(string $firstname = ''): string
{
    return 'Hello ' . ($firstname == '' ? 'World!' : $firstname);
}

echo sayHello();
```

> **Am I happy with this? Oh yes!!!:**
>
> Yes, I'm very happy and proud to see how my code is now better and easier to read.
>
> Yes, I'm happy to have learned something and, now, I'll no more use a temporary variable or think to use the ternary operator.
>
> Yes, I'm very grateful to Rector for teaching me these new approaches and making me a better programmer.

## Last thing, make the change

Now that we've taken the time to analyze the rules that could be applied and that we think are perfectly adequate, it's time to start refactoring for real: simply remove the `--dry-run` flag and, thus, the final command to run is: `vendor/bin/rector process sayHello.php --config rector.php`.

Imagine what it could do for my entire project if I run `vendor/bin/rector process . --dry-run --config rector.php`.

## Conclusion

A linter tells you that a line is wrong. Rector tells you what it would write instead, and names the rule so you can go read why. That's the difference between a tool that grades you and a coach that teaches you — and after a few sessions, you stop writing the useless temporary variable in the first place.

There are more than 400 rules right now; see all of them at <https://getrector.com/documentation/rules-overview>, and visit <https://getrector.com/> to learn how to configure `rector.php` for your own project.

Rector is just one piece of my PHP code-quality toolbox; see also [formatting poorly formatted PHP code](/blog/online-php-linter).
