Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Post: Laravel facades vs class aliases #68

Merged
merged 6 commits into from
Mar 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions source/_posts/laravel-facades-vs-class-aliases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: Laravel facades vs class aliases
date: 2024-03-26
excerpt: Diving into the difference between Laravel's facades and class aliases.
extends: _layouts.post
section: body
---

There's a difference between what Laravel calls facades and class aliases. Let's
take a look at both, how they're different from each other, and how they became
so intertwined with each other in the public eye.

## Facades
A facade in Laravel is nothing but _a proxy_ to an object in the service container.
In other words, if an object is bound to the service container as `'my-service'`,
you can call methods on that object by using static methods on the following
facade:

```php
namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class MyServiceFacade extends Facade
{
public function getFacadeAccessor()
{
return 'my-service';
}
}
```

Notice the `'my-service'` string by which the service is bound to the container.
When _any_ static method is called on this facade,
[the facade's `__callStatic()`magic method](https://github.com/laravel/framework/blob/428f86d2734d7ce4a40b3826bf78500c395b419d/src/Illuminate/Support/Facades/Facade.php#L349-L358) is invoked, the `'my-service'`
service is retrieved from the container, and your call is forwarded to that
instance.

You still have to reference the full namespace to this facade (`App\Facades\MyServiceFacade`)
when you use it in your application. At least, if you don't also add a class alias.

## Class Aliases
PHP allows developers to alias _any_ class to _any other name_ using
[the `class_alias` function](https://www.php.net/manual/en/function.class-alias.php). For example, say I have a class named `Aang`,
I could alias it to`BonzuPippinpaddleopsicopolisTheThird` and use it like normal:

```php
class Aang
{
public static function greet(): string
{
return 'Flameo!';
}
}

class_alias(Aang::class, 'BonzuPippinpaddleopsicopolisTheThird');

echo BonzuPippinpaddleopsicopolisTheThird::greet(); // Flameo!
```

You can also alias something to another namespace if you want:

```php
namespace App {
class User
{
public static function greet(): string
{
return 'Hello!';
}
}
}

namespace {
class_alias(App\User::class, 'User');

echo \User::greet(); // Hello!
}
```

This can be useful for using classes with a long FQCN in views, where importing
classes with `use` statements might not be possible or is just plain ugly.

The most obvious downside is that you lose autocomplete in most IDEs, because your
IDE can't know when/if the `class_alias()` function has been called at that point
in your application.

## The Confusion
Laravel aliases all facades it ships with to their base classname like in the second
example above. That means
[all classes in the `Illuminate\Support\Facades` namespace](https://github.com/laravel/framework/tree/428f86d2734d7ce4a40b3826bf78500c395b419d/src/Illuminate/Support/Facades)
are available as if they were in the global namespace. You can see this happen in your
own `config/app.php` (the `aliases` key).

I think this default behavior is why a lot of people in the Laravel community have
conflated facades and class aliases.

Using a namespaced class as if it lives in the global namespace is not only for
facades. You can alias whatever classes you want in the aforementioned `config/app.php`.
For example, you might alias `Illuminate\Support\Str` to just `Str` and
`Illuminate\Support\Number` to `Num` for quick and easy use in views.

## Conclusion
`\Config` is not a _facade_, it's a class alias for the facade. There is no reason
why you shouldn't import the full namespace to a facade in PHP-only files.

I generally think that you should import the full namespace
(`use Illuminate\Support\Facades\Config`) for facades, and not the alias. I also
try to limit the use of class aliases in views and opt for the global functions
Laravel provides instead because aliases don't work with autocomplete in my IDE
without external tooling.
Loading