Facades in Laravel allows you to call non-static methods as if they were static methods. This makes it possible for you to call methods in certain classes without the need for creating an object everytime you use them. It basically has the same benefit of using the service container.
Before we look into how we can implement our own Facades with Laravel, let's first take a look at a few examples on how Laravel uses Facades.
The Laravel framework stores its Facades in the vendor/laravel/frameworks/src/Illuminate/Support/Facades
directory. There you will see familiar one's such as DB.php
, View.php
, Validator.php
, and Request.php
. If you open any of these files, you will see some code which looks like the following:
class DB extends Facade
{
protected static function getFacadeAccessor()
{
return 'db';
}
}
This class extends the Facade
class (Facade.php
in the same directory). If you open that up, you'll see a bunch of methods for testing purposes. We're not gonna go over those today. Instead, we'll focus on the __callStatic
method. What this methos does is call the getFacadeAccesor()
method in the extending class (e.g the DB
class) and resolves an instance of the class being returned by that method. In this case, it's the db
class.
That sounds really confusing even if you tried tracing through the method calls in the base Facade
class. So let's go through a simpler example first.
Create an app/ShowName.php
file and add the following:
<?php
namespace App;
class ShowName {
public static function __callStatic($method, $arguments)
{
dd($method);
}
}
Then in your routes/web.php
file, add the following route.
Route::get('show', function(App\ShowName $obj) {
$obj::someMethodName('cat', 'dog');
});
That should then output "somemethodName" or whatever method you called.
You can also get access to the arguments passed to the method from here:
dd($arguments);
That should then show the following output:
array:2 [▼
0 => "cat"
1 => "dog"
]
That's the basic idea behind how Facades work. The Facade has this __callStatic()
method which then resolves the underlying from the service container. This means that Facades aren't really a replacement to using the service container. It's a supplement to make methods even more easier to call.
Now that you know how Facades work behind the scenes, let's now try to implement one ourselves.
Open the app/ShowName.php
file from earlier and update the __callStatic()
method with the following:
public static function __callStatic($method, $arguments)
{
return (self::resolveFacade('ShowName'))->$method(...$arguments);
}
Then add this method:
public static function resolveFacade($name)
{
return app()[$name];
}
This method resolves the specific class from the service container. This will only work if you bind the Facade in your app service provider:
// app/Providers/AppServiceProvider.php
$this->app->bind('ShowName', function () {
return new ShowNameService;
});
The ShowNameService
contains the following:
<?php
// app/Services/ShowNameService.php
namespace App\Services;
class ShowNameService {
public function hello($name)
{
return 'hello ' . $name;
}
}
Next, open your config/app.php
file and add a new item to the aliases
array.
'aliases' => [
// ...
'ShowName' => App\ShowName::class, // add this
],
Once that's done, you should now be able to call methods from the ShowNameService
class using the ShowName
facade.
Route::get('hello', function() {
return ShowName::hello('cat'); // outputs: "hello cat"
});
If you then add a new method on your ShowNameService
class:
public function hi($name)
{
return 'hi ' . $name;
}
You should still be able to call it through the Facade:
ShowName::hi('cat'); // outputs: "hi cat"
Cover image from matthaeus: https://unsplash.com/photos/hew8vAvvvz4
Top comments (0)