Фасады Laravel
Фасады Laravel

Фасады Laravel



Введение

В документации Laravel вы увидите примеры кода, который взаимодействует с функциями Laravel через «фасады». Фасады предоставляют «статический» интерфейс для классов, доступных в сервисном контейнере приложения. Laravel поставляется с множеством фасадов, которые обеспечивают доступ почти ко всем функциям Laravel.

Фасады Laravel служат «статическими прокси» для базовых классов в сервисном контейнере, обеспечивая преимущества краткого выразительного синтаксиса при сохранении большей тестируемости и гибкости, чем традиционные статические методы. Это прекрасно, если вы не совсем понимаете, как фасады работают под капотом - просто плывите по течению и продолжайте изучать Laravel.

Все фасады Laravel определены в пространстве имен Illuminate\Support\Facades. Итак, мы можем легко получить доступ к такому фасаду:

use Illuminate\Support\Facades\Cache;

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

В документации Laravel во многих примерах будут использоваться фасады для демонстрации различных функций фреймворка.

Вспомогательные функции (хэлперы)

В дополнение к фасадам Laravel предлагает множество глобальных «вспомогательных функций» (helper functions), которые упрощают взаимодействие с общими функциями Laravel. Некоторые из общих вспомогательных функций, с которыми вы можете взаимодействовать, - это view, response, url, config и другие. Каждая вспомогательная функция, предлагаемая Laravel, документирована с соответствующей функцией; однако полный список доступен в специальной документации по хэлперам.

Например, вместо использования фасада Illuminate\Support\Facades\Response для генерации ответа JSON мы можем просто использовать функцию response. Поскольку вспомогательные функции глобально доступны, вам не нужно импортировать какие-либо классы, чтобы использовать их:

use Illuminate\Support\Facades\Response;

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

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

Когда использовать фасады в Laravel

У фасадов много преимуществ. Они обеспечивают краткий запоминающийся синтаксис, который позволяет вам использовать функции Laravel, не запоминая длинные имена классов, которые необходимо вводить или настраивать вручную. Более того, благодаря уникальному использованию динамических методов PHP их легко протестировать.

Однако при использовании фасадов необходимо соблюдать некоторую осторожность. Основная опасность фасадов - это класс «ползучесть» (scope creep). Поскольку фасады настолько просты в использовании и не требуют инъекций, можно легко позволить вашим классам продолжать расти и использовать множество фасадов в одном классе. При использовании внедрения зависимостей этот потенциал снижается за счет визуальной обратной связи, которую дает большой конструктор потому, что ваш класс становится слишком большим. Поэтому, используя фасады, обратите особое внимание на размер вашего класса, чтобы объем его ответственности оставался узким. Если ваш класс становится слишком большим, рассмотрите возможность разделения его на несколько более мелких классов.

Фасады Vs. Внедрение зависимости

Одним из основных преимуществ внедрения зависимостей является возможность поменять местами реализации внедренного класса. Это полезно во время тестирования, так как вы можете вставить имитацию или заглушку и утверждать, что для заглушки были вызваны различные методы.

Как правило, невозможно издеваться над действительно статическим методом класса или заглушить его. Однако, поскольку фасады используют динамические методы для проксирования вызовов методов к объектам, разрешенным из контейнера службы, мы фактически можем тестировать фасады так же, как мы тестировали бы внедренный экземпляр класса. Например, учитывая следующий маршрут:

use Illuminate\Support\Facades\Cache;

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

Используя методы тестирования фасада Laravel, мы можем написать следующий тест, чтобы убедиться, что метод Cache::get был вызван с ожидаемым аргументом:

use Illuminate\Support\Facades\Cache;

/**
 * Пример базового функционального теста.
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

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

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

Фасады Vs. Вспомогательные функции

Помимо фасадов, Laravel включает в себя множество «вспомогательных» функций, которые могут выполнять общие задачи, такие как генерация представлений, запуск событий, диспетчеризация заданий или отправка HTTP-ответов. Многие из этих вспомогательных функций выполняют ту же функцию, что и соответствующий фасад. Например, этот вызов фасада и вызов помощника эквивалентны:

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

return view('profile');

Практической разницы между фасадами и вспомогательными функциями нет абсолютно никакой. При использовании вспомогательных функций вы все равно можете тестировать их точно так же, как и соответствующий фасад. Например, учитывая следующий маршрут:

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

Под капотом хэлпера cache будет вызываться метод get для класса, лежащего в основе фасада Cache. Итак, даже если мы используем вспомогательную функцию, мы можем написать следующий тест, чтобы убедиться, что метод был вызван с ожидаемым аргументом:

use Illuminate\Support\Facades\Cache;

/**
 * Пример базового функционального теста.
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

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

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

Как работают фасады в Laravel

В приложении Laravel фасад - это класс, который предоставляет доступ к объекту из контейнера. Техника, которая выполняет эту работу, относится к классу Facade. Фасады Laravel и любые пользовательские фасады, которые вы создаете, будут расширять базовый класс Illuminate\Support\Facades\Facade.

Базовый класс Facade использует магический метод __callStatic (), чтобы отложить вызовы вашего фасада на объект, разрешенный из контейнера. В приведенном ниже примере выполняется вызов кэш-системы Laravel. Взглянув на этот код, можно предположить, что статический метод get вызывается в классе Cache:

<?php

namespace App\Http\Controllers;

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

class UserController extends Controller
{
    /**
     * Показать профиль данного пользователя.
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Cache::get('user:'.$id);

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

Обратите внимание, что в верхней части файла мы «импортируем» фасад Cache. Этот фасад служит прокси для доступа к базовой реализации интерфейса Illuminate\Contracts\Cache\Factory. Любые вызовы, которые мы делаем с использованием фасада, будут передаваться в базовый экземпляр службы кеширования Laravel.

Если мы посмотрим на этот класс Illuminate\Support\Facades\Cache, вы увидите, что нет статического метода get:

class Cache extends Facade
{
    /**
     * Получите зарегистрированное имя компонента.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }
}

Вместо этого фасад Cache расширяет базовый класс Facade и определяет метод getFacadeAccessor(). Задача этого метода - вернуть имя привязки контейнера службы. Когда пользователь ссылается на какой-либо статический метод на фасаде Cache, Laravel разрешает привязку cache из сервисного контейнера и запускает запрошенный метод (в данном случае get) для этого объекта.

Фасады в реальном времени

Используя фасады в реальном времени, вы можете рассматривать любой класс в своем приложении, как если бы он был фасадом. Чтобы проиллюстрировать, как это можно использовать, давайте сначала рассмотрим код, который не использует фасады в реальном времени. Например, предположим, что наша модель Podcast имеет метод publish. Однако, чтобы опубликовать подкаст, нам нужно внедрить экземпляр Publisher:

<?php

namespace App\Models;

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

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

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

Внедрение реализации издателя (publisher) в метод позволяет нам легко тестировать метод изолированно, поскольку мы можем имитировать внедренного издателя. Однако это требует от нас всегда передавать экземпляр издателя каждый раз, когда мы вызываем метод publish. Используя фасады в реальном времени, мы можем поддерживать такую же тестируемость, не требуя явной передачи экземпляра Publisher. Чтобы создать фасад в реальном времени, добавьте к пространству имен импортированного класса префикс Facades:

<?php

namespace App\Models;

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

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

        Publisher::publish($this);
    }
}

Когда используется фасад реального времени, реализация издателя будет разрешена из контейнера службы с использованием части интерфейса или имени класса, которая появляется после префикса Facades. При тестировании мы можем использовать встроенные помощники Laravel по тестированию фасадов, чтобы имитировать вызов этого метода:

<?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.
     *
     * @return void
     */
    public function test_podcast_can_be_published()
    {
        $podcast = Podcast::factory()->create();

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

        $podcast->publish();
    }
}

Справочник классов фасадов Laravel

Ниже вы найдете каждый фасад и его базовый класс. Это полезный инструмент для быстрого изучения документации API для данного корня фасада. Ключ привязки контейнера службы также включен, где это применимо.

Facade Class Service Container Binding
App Illuminate\Foundation\Application app
Artisan Illuminate\Contracts\Console\Kernel artisan
Auth Illuminate\Auth\AuthManager auth
Auth (Instance) Illuminate\Contracts\Auth\Guard auth.driver
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Broadcast Illuminate\Contracts\Broadcasting\Factory  
Broadcast (Instance) Illuminate\Contracts\Broadcasting\Broadcaster  
Bus Illuminate\Contracts\Bus\Dispatcher  
Cache Illuminate\Cache\CacheManager cache
Cache (Instance) Illuminate\Cache\Repository cache.store
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
Crypt Illuminate\Encryption\Encrypter encrypter
DB Illuminate\Database\DatabaseManager db
DB (Instance) Illuminate\Database\Connection db.connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Gate Illuminate\Contracts\Auth\Access\Gate  
Hash Illuminate\Contracts\Hashing\Hasher hash
Http Illuminate\Http\Client\Factory  
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\LogManager log
Mail Illuminate\Mail\Mailer mailer
Notification Illuminate\Notifications\ChannelManager  
Password Illuminate\Auth\Passwords\PasswordBrokerManager auth.password
Password (Instance) Illuminate\Auth\Passwords\PasswordBroker auth.password.broker
Queue Illuminate\Queue\QueueManager queue
Queue (Instance) Illuminate\Contracts\Queue\Queue queue.connection
Queue (Base Class) Illuminate\Queue\Queue  
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\RedisManager redis
Redis (Instance) Illuminate\Redis\Connections\Connection redis.connection
Request Illuminate\Http\Request request
Response Illuminate\Contracts\Routing\ResponseFactory  
Response (Instance) Illuminate\Http\Response  
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Builder  
Session Illuminate\Session\SessionManager session
Session (Instance) Illuminate\Session\Store session.store
Storage Illuminate\Filesystem\FilesystemManager filesystem
Storage (Instance) Illuminate\Contracts\Filesystem\Filesystem filesystem.disk
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator (Instance) Illuminate\Validation\Validator  
View Illuminate\View\Factory view
View (Instance) Illuminate\View\View  

Перевод:
https://laravel.com/docs/8.x/facades

Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)

Старт! Горячий старт на просторы интернета
Старт! Горячий старт на просторы интернета
Старт! Меню