Фасады Laravel
- Введение
- Когда использовать фасады в 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 для данного корня фасада. Ключ привязки контейнера службы также включен, где это применимо.
Перевод:
https://laravel.com/docs/8.x/facades
Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)