Facades
A facade provides a static-looking interface to a class resolved from the service container. Cache::get(), DB::table(), and Route::get() are facades. Behind the scenes, the call is forwarded to a real object, which keeps testability and dependency injection intact.
How a facade works
Each facade defines getFacadeAccessor(), which returns a container key. When you call a static method, the base facade resolves that key and forwards the call.
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Sms extends Facade
{
protected static function getFacadeAccessor(): string
{
return 'sms';
}
}
Registering the binding
use App\Services\SmsGateway;
public function register(): void
{
$this->app->singleton('sms', function ($app) {
return new SmsGateway($app['config']['services.sms']);
});
}
use App\Facades\Sms;
Sms::send($number, 'Your code is 4821');
Real-time facades
Any class can be used like a facade by prefixing its namespace with Facades\. This is convenient in quick scripts and tests, but explicit injection is usually clearer in application code.
use Facades\App\Services\InvoiceCalculator;
$total = InvoiceCalculator::total($items);
Facades versus injection
Constructor injection makes dependencies visible and easy to replace in tests. Facades shorten code and are convenient in views and legacy sections. A balanced approach is to inject services into controllers and use facades for framework utilities such as Cache, Log, and DB.
// injected dependency
public function __construct(private InvoiceCalculator $calculator)
{
}
// framework utility
$value = Cache::remember('stats', 600, fn () => $this->calculator->stats());
Testing with facades
Laravel's facades include fake helpers for framework services. For custom facades, swap the binding in the container or mock the underlying class.
Cache::shouldReceive('get')
->once()
->with('stats')
->andReturn(['users' => 10]);
Mail::fake();
Queue::fake();
Bus::fake();
Common pitfalls
- Forgetting to register the container binding behind a custom facade.
- Using real-time facades in hot paths where a normal dependency would be clearer.
- Assuming facades are globally available in every namespace; import them explicitly.
- Mocking a facade when a fake is available; fakes preserve more framework behavior.