Вы когда-нибудь использовали Auth::user()
в Laravel? Так что Auth
да, это фасад. Вопрос: нужно ли вам на самом деле знать, как они работают, и нужно ли создавать свои собственные фасады?
Отказ от ответственности: эта статья написана Modestas, больше похожа на мнение. Фасады — одна из тех тем, которые имеют разные мнения о них, поэтому я открыт для дискуссий здесь или в Twitter.
Что такое фасады?
Во-первых, определение.
Читая документацию Laravel о фасадах, вы можете немного запутаться в том, что они собой представляют. В документации говорится:
Фасады предоставляют «статический» интерфейс для классов, доступных в контейнере служб приложения.
Наряду с этим, они также говорят:
Laravel Facades служат «статическими прокси» для базовых классов в сервисном контейнере, обеспечивая преимущество краткого, выразительного синтаксиса, сохраняя при этом большую проверяемость и гибкость, чем традиционные статические методы.
Подождите, что это на самом деле значит?
Ну, вам не нужно будет знать, какой класс находится под фасадом. Вы можете просто вызвать Auth
façade и получить доступ к методам из базового класса.
Фасады в действии
В Laravel мы можем вызватьAuth::user()
, чтобы извлечь пользователя из сеанса.
То, что мы не видим под капотом, это статический прокси для Illuminate\Auth\AuthManager
класса. Класс AuthManager
имеет методuser()
, который возвращает пользователя из сеанса.
Facade облегчает наш опыт как разработчиков, так как нам нужно только помнить Auth
фасад, и мы получаем мгновенный статический доступ к методуuser()
.
Давайте быстро сравним использование фасада с использованием самого класса, чтобы проиллюстрировать разницу.
Как бы это выглядело без фасадов?
Создание нового экземпляра
use Illuminate\Auth\AuthManager;
public function index()
{
$auth = new AuthManager();
$user = $auth->user();
}
класса Или, немного короче, с внедрением зависимостей.
Использование внедрения
use Illuminate\Auth\AuthManager;
public function index(AuthManager $auth)
{
$user = $auth->user();
}
зависимостей С фасадом под капотом, это всего лишь одна линия.
Использование фасада
public function index()
{
$user = Auth::user();
}
Короче говоря, фасады — это как ярлык для определенного класса.
Теперь, когда мы знаем, что это такое, давайте подумаем, нужно ли нам их использовать и как.
ИСПОЛЬЗОВАНИЕ фасадов - это здорово
Давайте начнем с того, что я считаю хорошим в использовании фасадов.
Используйте фасады из Framework Core
Удобно использовать фасады из ядра Laravel. Это просто работает, и вам не нужно запоминать какие-либо длинные имена классов.
Отлично подходит для тех, кто учится работать. Отлично подходит для тех, кто быстро разрабатывает системы.
Представьте себе, если бы вам пришлось запомнить все это:
Гораздо лучше быстро запомнить их фасады и использовать их:
Использовать фасады из пакетов
Создатели пакета также могут извлечь выгоду из фасадов по той же причине, что и в самом фреймворке - легче запомнить название фасада, чем название класса. Давайте рассмотрим несколько примеров пакетов:
Spatie Activity Logs
https://spatie.be/docs/laravel-activitylog/v4/advanced-usage/batch-logs
В этом пакете мы можем LogBatch
найти Facade, который является ярлыком для Spatie\Activitylog\LogBatch
класса.
Ларавель Отладчик
https://github.com/barryvdh/laravel-debugbar Этот пакет также содержит вызываемый Debugbar
элемент Facade, который является ярлыком Barryvdh\Debugbar\LaravelDebugbar
для класса.
Это просто дает конечному пользователю лучшее взаимодействие для использования некоторых функций в любой точке статически.
СОЗДАНИЕ собственных фасадов: не так здорово
О, круто, поэтому вы могли бы подумать, что можете создать свои собственные «ярлыки» фасадов и использовать их в любом месте вашего приложения Laravel?
И вот та часть, где, я думаю, фасады не так хороши. При неправильном использовании они могут вызвать проблемы с оснасткой или общим опытом.
Проблемы с автозаполнением
При использовании Фасадов у вас нет доступа к методам, доступным в классе. Это может вызвать некоторые проблемы с автозаполнением в среде IDE.
Например, представьте, что у вас есть класс SearchService
Service, который имеет метод с именем get()
:
app/Services/SearchService.php
namespace App\Services\SearchService;
class SearchService
{
public function get(string $query): array
{
// ...
}
}
Чтобы создать «ярлык» для него, вы создаете Facade с именем Search
:
app/Facades/Search.php
namespace App\Services\Facades;
use Illuminate\Support\Facades\Facade;
class Search extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Services\SearchService::class;
}
}
Так что теперь вы можете использовать Search::get()
, верно?
Круто, но ваша среда IDE может не показать, что класс существует или что у него нет никаких методов!
И это правда, потому что в вашем классе Facade нет get()
метода.
Вы можете заставить автозаполнение IDE работать, добавив блоки doc в класс Facade:
app/Facades/Search.php
namespace App\Services\Facades;
/**
* @method static get(string $query)
*/
class Search extends Facade {
// ...
}
Но вам также придется управлять другим файлом, чтобы убедиться, что все методы добавлены в Facade. Кажется сложным.
Фасады могут переопределять имена классов
При создании фасада не нужно следовать тому же имени класса, которое вы собираетесь вызывать. Это означает, что я могу использовать любое имя, которое я хочу для фасада, и оно все равно будет работать. Давайте рассмотрим пример:
Созданиеконфигурации/приложения Facade
class MyRandomClassName extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Services\SearchService::class;
}
}
.php
// ...
'aliases' => Facade::defaultAliases()->merge([
// ...
'MyRandomClassName' => \App\Services\Facades\MyRandomClassName::class,
])->toArray(),
Использование
\MyRandomClassName::get('query');
фасадаИ теперь я могу использовать MyRandomClassName
фасад для вызова Search
класса. Импорт не требуется, так как вы можете получить к нему доступ во всем мире.
Еще хуже тот факт, что этот класс может даже не существовать! Как? Ну, мы создаем псевдоним. Давайте изменим config
немного:
.php
// ...
'aliases' => Facade::defaultAliases()->merge([
// ...
'MadeUpAlias' => \App\Services\Facades\MyRandomClassName::class,
])->toArray(),
Использование
\MadeUpAlias::get('query');
фасадаИ это все равно будет работать! Но если вы попытаетесь искать глобальноMadeUpAlias
, результатов не будет. Это потому, что это не настоящий класс. Это просто псевдоним для класса, который существует.
Примечание: Я знаю, что этот пример преувеличен. Но это дает вам отличный пример того, как вы можете использовать фасады неправильным образом, чтобы добавить больше путаницы в вашу кодовую базу.
Фасады могут быть использованы в любом месте
Одна вещь, которую фасады имеют для них, - это возможность использовать их в любом месте, где вы хотите. Отличная вещь, не так ли?
Вам это нужно в представлении, контроллере, службе или где-либо еще? Нет проблем - она есть.
Но это быстрый способ сломать шаблон MVC и запустить сложную логику там, где вам не положено.
Представьте, что вы создали фасад для службы, которая генерирует большую таблицу отчетов. Используйте его в контроллере, и это будет хорошо. Но используйте его в View, и у нас есть проблема.
Учебники по фасадам не показывают реальное использование
Когда вы смотрите на учебники о том, как создавать фасады, они, как правило, очень просты. Они являются просто ярлыком для класса, который возвращает что-то простое.
Но в реальных сценариях Facades предназначены для использования в качестве прокси-класса для получения статического доступа к методам, которые не являются статическими, как в Auth
Facade.
Когда он перестанет быть крутым, вы сможете быстро выйти из-под контроля и переместить все в фасады, которые быстро приведут вас к ползучести, и один класс может начать выполнять работу 10 других.
Вывод
я бы сказал, что фасады удобны и просты в использовании, начиная от каркаса и пакетов. Но если мы попробуем создать ваши фасады - эта история изменится. Тогда вы должны действительно знать, что вы делаете.
Было бы лучше подумать о том, как вы можете структурировать проект с различными шаблонами проектирования, чтобы избежать глобального класса (фасада), который можно вызвать в любом месте.
Как ты думаешь? Давайте обсудим в комментариях!