Skip to content

Facades

Introdução

Por toda a documentação, você verá exemplos de código que interagem com os recursos por meio de "facades". As facades fornecem uma interface "estática" para classes que estão disponíveis no service container. O Laravel vem com muitas facades que fornecem acesso a quase todos os recursos do Laravel.

As facades do Laravel servem como "proxies estáticos" para classes subjacentes no service container, fornecendo o benefício de uma sintaxe concisa e expressiva, mantendo mais testabilidade e flexibilidade do que os métodos estáticos tradicionais. Está tudo bem se você não entender totalmente como as facades funcionam - apenas siga em frente e continue aprendendo sobre o Laravel.

Todas as facades do Laravel são definidas no namespace Illuminate\Support\Facades. Portanto, podemos acessar uma facade facilmente assim:

php
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;

Route::get('/cache', function () {
    return Cache::get('key');
});

Por toda a documentação, muitos dos exemplos usarão facades para demonstrar vários recursos do framework.

Helper Functions

Para complementar as facades, o Laravel oferece uma variedade de "funções auxiliares" globais que tornam ainda mais fácil interagir com recursos comuns do Laravel. Algumas das funções auxiliares comuns com as quais você pode interagir são view, response, url, config e muito mais. Cada função auxiliar oferecida pelo Laravel é documentada com seu recurso correspondente; no entanto, uma lista completa está disponível na documentação dedicada sobre funções auxiliares.

Por exemplo, em vez de usar a facade Illuminate\Support\Facades\Response para gerar uma resposta JSON, podemos simplesmente usar a função response. Como as funções auxiliares estão globalmente disponíveis, você não precisa importar nenhuma classe para usá-las:

php
use Illuminate\Support\Facades\Response;

Route::get('/users', function () {
    return Response::json([
        // ...
    ]);
});

Route::get('/users', function () {
    return response()->json([
        // ...
    ]);
});

Quando Utilizar Facades

As facades têm muitos benefícios. Elas fornecem uma sintaxe concisa e que permite que você use os recursos do Laravel sem precisar lembrar de nomes longos de classes que devem ser injetadas ou configuradas manualmente. Além disso, devido ao uso exclusivo dos métodos dinâmicos do PHP, elas são fáceis de testar.

No entanto, é preciso ter cuidado ao usar facades. O principal perigo das facades é o "escopo da classe". Como as facades são tão fáceis de usar e não requerem injeção, pode ser fácil deixar suas classes continuarem crescendo e usar muitas facades em uma única classe. Usando injeção de dependência, esse potencial é mitigado pelo feedback visual de um grande construtor que lhe dá a impressão de que sua classe está crescendo demais. Portanto, ao usar facades, preste atenção especial ao tamanho de sua classe para que seu escopo de responsabilidade permaneça estreito. Se sua classe estiver ficando muito grande, considere dividi-la em várias classes menores.

Facades vs. Injeção de Dependência

Um dos principais benefícios da injeção de dependência é a capacidade de trocar implementações da classe injetada. Isso é útil durante os testes, pois você pode injetar um mock ou stub e afirmar que vários métodos foram chamados no stub.

Normalmente, não seria possível mockar um método de classe verdadeiramente estático. No entanto, como as facades usam métodos dinâmicos para fazer chamadas de método a objetos resolvidos do service container, na verdade podemos testar facades da mesma forma que testaríamos uma instância de classe injetada. Por exemplo, dado o seguinte roteamento:

php
use Illuminate\Support\Facades\Cache;

Route::get('/cache', function () {
    return Cache::get('key');
});

Usando os métodos de teste de facades, podemos escrever o seguinte teste para verificar se o método Cache::get foi chamado com o argumento que esperávamos:

php
use Illuminate\Support\Facades\Cache;

test('exemplo básico', function () {
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
});
php
use Illuminate\Support\Facades\Cache;

/**
 * Um exemplo básico de teste funcional.
 */
public function test_exemplo_basico(): void
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
}

Facades vs. Helper Functions

Além das facades, o Laravel inclui uma variedade de "funções auxiliares" que podem realizar tarefas comuns, como gerar views, disparar eventos, disparar jobs ou enviar responses HTTP. Muitas dessas funções auxiliares realizam a mesma função que uma facade correspondente. Por exemplo, esta chamada de facade e chamada de função auxiliar são equivalentes:

php
return Illuminate\Support\Facades\View::make('profile');

return view('profile');

Na prática, não há diferença entre facades e funções auxiliares. Ao usar funções auxiliares, você ainda pode testá-las exatamente como faria com a facade correspondente. Por exemplo, dado o seguinte roteamento:

php
Route::get('/cache', function () {
    return cache('key');
});

O helper cache vai chamar o método get na classe subjacente da facade Cache. Portanto, mesmo que estejamos usando a função auxiliar, podemos escrever o seguinte teste para verificar se o método foi chamado com o argumento que esperávamos:

php
use Illuminate\Support\Facades\Cache;

/**
 * Um exemplo básico de teste funcional.
 */
public function test_exemplo_basico(): void
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
}

Como as Facades Funcionam

Em uma aplicação Laravel, uma facade é uma classe que fornece acesso a um objeto do container. O mecanismo que faz isso funcionar está na classe Facade. As facades do Laravel, e quaisquer facades personalizadas que você criar, estenderão a classe base Illuminate\Support\Facades\Facade.

A classe base Facade faz uso do método mágico __callStatic() para adiar chamadas de sua facade para um objeto resolvido do container. No exemplo abaixo, uma chamada é feita ao sistema de cache do Laravel. Ao olhar para este código, alguém poderia assumir que o método estático get está sendo chamado na classe Cache:

php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     */
    public function showProfile(string $id): View
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}

Observe que no início do arquivo estamos "importando" a facade Cache. Esta facade serve como um atalho para acessar a implementação subjacente da interface Illuminate\Contracts\Cache\Factory. Qualquer chamada feita usando a facade será direcionada para a instância real do serviço de cache do Laravel.

Se olharmos para a classe Illuminate\Support\Facades\Cache, veremos que não há um método estático get:

php
class Cache extends Facade
{
    /**
     * Get the registered name of the component.
     */
    protected static function getFacadeAccessor(): string
    {
        return 'cache';
    }
}

Em vez disso, a facade Cache estende a classe base Facade e define o método getFacadeAccessor(). A função deste método é retornar o nome de um binding do service container. Quando um usuário referencia qualquer método estático na facade Cache, o Laravel resolve o binding cache do service container e chama o método solicitado no objeto retornado.

Real-Time Facades

Usando real-time facades, você pode tratar qualquer classe em sua aplicação como se fosse uma facade. Para ilustrar como isso pode ser usado, vamos primeiro examinar algum código que não usa facades em tempo real. Por exemplo, vamos assumir que nosso model Podcast tem um método publish. No entanto, para publicar o podcast, precisamos injetar uma instância de Publisher:

php
<?php

namespace App\Models;

use App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * Publish the podcast.
     */
    public function publish(Publisher $publisher): void
    {
        $this->update(['publishing' => now()]);

        $publisher->publish($this);
    }
}

Injetar uma implementação de publisher no método nos permite testar facilmente o método de forma isolada, pois podemos simular o publisher injetado. No entanto, isso requer que sempre passemos uma instância de Publisher cada vez que chamamos o método publish. Usando real-time facades, podemos manter a mesma testabilidade sem sermos obrigados a passar explicitamente uma instância de Publisher. Para gerar uma real-time facade, prefixe o namespace da classe importada com Facades:

php
<?php

namespace App\Models;

use App\Contracts\Publisher;  
use Facades\App\Contracts\Publisher;  
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * Publish the podcast.
     */
    public function publish(Publisher $publisher): void
    public function publish(): void
    {
        $this->update(['publishing' => now()]);

        $publisher->publish($this); 
        Publisher::publish($this); 
    }
}

Quando a real-time facade é usada, a implementação do publisher será resolvida do service container usando a parte da interface ou nome da classe que aparece após o prefixo Facades. Ao testar, podemos usar os auxiliares de teste de facade integrados do Laravel para simular essa chamada de método:

php
<?php

use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('podcast can be published', function () {
    $podcast = Podcast::factory()->create();

    Publisher::shouldReceive('publish')->once()->with($podcast);

    $podcast->publish();
});
php
<?php

namespace Tests\Feature;

use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PodcastTest extends TestCase
{
    use RefreshDatabase;

    /**
     * A test example.
     */
    public function test_podcast_can_be_published(): void
    {
        $podcast = Podcast::factory()->create();

        Publisher::shouldReceive('publish')->once()->with($podcast);

        $podcast->publish();
    }
}

Referência de Classes de Facade

Abaixo você encontrará todas as facades e suas classes subjacentes. Esta é uma ferramenta útil para mergulhar rapidamente na documentação da API para uma determinada raiz de facade. A chave de binding do service container também é incluída quando aplicável.

FacadeClasseBinding do Container
AppIlluminate\Foundation\Applicationapp
ArtisanIlluminate\Contracts\Console\Kernelartisan
Auth (Instance)Illuminate\Contracts\Auth\Guardauth.driver
AuthIlluminate\Auth\AuthManagerauth
BladeIlluminate\View\Compilers\BladeCompilerblade.compiler
Broadcast (Instance)Illuminate\Contracts\Broadcasting\Broadcaster
BroadcastIlluminate\Contracts\Broadcasting\Factory
BusIlluminate\Contracts\Bus\Dispatcher
Cache (Instance)Illuminate\Cache\Repositorycache.store
CacheIlluminate\Cache\CacheManagercache
ConfigIlluminate\Config\Repositoryconfig
ContextIlluminate\Log\Context\Repository
CookieIlluminate\Cookie\CookieJarcookie
CryptIlluminate\Encryption\Encrypterencrypter
DateIlluminate\Support\DateFactorydate
DB (Instance)Illuminate\Database\Connectiondb.connection
DBIlluminate\Database\DatabaseManagerdb
EventIlluminate\Events\Dispatcherevents
Exceptions (Instance)Illuminate\Contracts\Debug\ExceptionHandler
ExceptionsIlluminate\Foundation\Exceptions\Handler
FileIlluminate\Filesystem\Filesystemfiles
GateIlluminate\Contracts\Auth\Access\Gate
HashIlluminate\Contracts\Hashing\Hasherhash
HttpIlluminate\Http\Client\Factory
LangIlluminate\Translation\Translatortranslator
LogIlluminate\Log\LogManagerlog
MailIlluminate\Mail\Mailermailer
NotificationIlluminate\Notifications\ChannelManager
Password (Instance)Illuminate\Auth\Passwords\PasswordBrokerauth.password.broker
PasswordIlluminate\Auth\Passwords\PasswordBrokerManagerauth.password
Pipeline (Instance)Illuminate\Pipeline\Pipeline
ProcessIlluminate\Process\Factory
Queue (Base Class)Illuminate\Queue\Queue
Queue (Instance)Illuminate\Contracts\Queue\Queuequeue.connection
QueueIlluminate\Queue\QueueManagerqueue
RateLimiterIlluminate\Cache\RateLimiter
RedirectIlluminate\Routing\Redirectorredirect
Redis (Instance)Illuminate\Redis\Connections\Connectionredis.connection
RedisIlluminate\Redis\RedisManagerredis
RequestIlluminate\Http\Requestrequest
Response (Instance)Illuminate\Http\Response
ResponseIlluminate\Contracts\Routing\ResponseFactory
RouteIlluminate\Routing\Routerrouter
ScheduleIlluminate\Console\Scheduling\Schedule
SchemaIlluminate\Database\Schema\Builder
Session (Instance)Illuminate\Session\Storesession.store
SessionIlluminate\Session\SessionManagersession
Storage (Instance)Illuminate\Contracts\Filesystem\Filesystemfilesystem.disk
StorageIlluminate\Filesystem\FilesystemManagerfilesystem
URLIlluminate\Routing\UrlGeneratorurl
Validator (Instance)Illuminate\Validation\Validator
ValidatorIlluminate\Validation\Factoryvalidator
View (Instance)Illuminate\View\View
ViewIlluminate\View\Factoryview
ViteIlluminate\Foundation\Vite