Laravel Facades to Constructor Injection: Replace Facade Aliases with Full Classes in 2 hours

Laravel facades are known as static service locators. The idea is get any service anywhere, which comes very handy for project bootstrapping.

Around Laravel 6, released in March 2019, the Laravel community started moving away from facades towards clearly typed constructor injection.

Today we'll take 1st step to make it happen.

It was a big surprise for us that it's not only external critics of Laravel but also from inside the community itself. There is a proposal to remove facades completely in Laravel 6:


But as we well know, programmers are lazy:

"Give me the tools to solve my problem, and I'll consider it.
Give me an extra work, and I'll pass."

So, in the end, the discussion was closed, and nothing has changed. Yet, the spark that started a fire...

What the... Alias?

Aliases are defined in config/app.php under alias key. They're basically converted to:

// 'original class', 'alias'
class_alias('Some\LongerClass\App', 'App');

That means these 2 lines are identical:

App::run();
Some\LongerClass\App::run();

2 ways to do 1 thing is a code smell. It's also the low handing fruit we can make colossal leap to make our code base less magical.

As a bonus, we'll save few in config/app.php:

3 Steps to Remove Facade Aliases

Class alias is basically inverted class rename. So all we need to do si rename short classes (App) to long ones (Some\LongerClass\App), e.g.:

  1. Install Rector
composer require rector/rector --dev

# creates "rector.php"
vendor/bin/rector init
  1. Configure rector.php

Look how Laravel is helping us here. Just copy paste lines from config/app.phpaliases:

use Rector\Renaming\Rector\Name\RenameClassRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $services = $containerConfigurator->services();

    $services->set(RenameClassRector::class)
        ->call('configure', [[
            RenameClassRector::OLD_TO_NEW_CLASSES => [
                'App' => 'Illuminate\Support\Facades\App',
                'Artisan' => 'Illuminate\Support\Facades\Artisan',
                'Auth' => 'Illuminate\Support\Facades\Auth',
                'Blade' => 'Illuminate\Support\Facades\Blade',
                'Broadcast' => 'Illuminate\Support\Facades\Broadcast',
                'Bus' => 'Illuminate\Support\Facades\Bus',
                'Cache' => 'Illuminate\Support\Facades\Cache',
                'Config' => 'Illuminate\Support\Facades\Config',
                // ...
            ]
        ]]);
};
  1. Run Rector
vendor/bin/rector process src

That's it!


Blade Templates?

What are Blade templates in simple words? PHP files with syntax sugar.

Most Rector rules or static analysis would fail here, but Rector can rename classes even in non-standard PHP files like Blade, TWIG, Latte, Neon, or YAML. We rarely want to rename a class in PHP code and keep the old name in configs and templates.

Blade templates are covered too!


Real Case Study with Eonx

You're probably thinking: "Demo always looks nice. It's designed to look nice. But what about a real private project?" We're glad you doubt.

Recently, we applied this refactoring on a project of size 250 000-750 000 lines of code, in cooperation with Australian company, Eonx.

Here are all the pull-requests, we had to make:

The biggest pull-request has changed 45 600 lines.


The Numbers

  • we changed ~65 000 lines of code
  • it took ~15 hours of Rector configuration work and research (= the insights in this post)
  • and 4 hours of coding work and running Rector

Now the same work on the same project would take 2 hours in total. And we believe you can do it for your project too!


Happy refactoring!