Вступление
Фасады предоставляют «статический» интерфейс для классов, которые доступны в контейнере службы приложения. Laravel поставляется с множеством фасадов, которые обеспечивают доступ почти ко всем функциям Laravel. Фасады Laravel служат в качестве «статических посредников» для базовых классов в контейнере служб, обеспечивая преимущество краткого, выразительного синтаксиса, сохраняя при этом большую тестируемость и гибкость, чем традиционные статические методы.
Все фасады Laravel определены в пространстве имен. Таким образом, мы можем легко получить доступ к фасаду следующим образом:Illuminate\Support\Facades
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});
Во всей документации Laravel во многих примерах будут использоваться фасады для демонстрации различных функций каркаса.
Когда использовать фасады
Фасады имеют много преимуществ. Они предоставляют краткий, запоминающийся синтаксис, который позволяет вам использовать функции Laravel без запоминания длинных имен классов, которые необходимо вводить или настраивать вручную. Кроме того, благодаря уникальному использованию динамических методов PHP, их легко тестировать.
Тем не менее, следует соблюдать осторожность при использовании фасадов. Основная опасность фасадов - ползучесть класса. Поскольку фасады настолько просты в использовании и не требуют инъекций, может быть легко позволить вашим классам продолжать расти и использовать множество фасадов в одном классе. Используя внедрение зависимостей, этот потенциал смягчается визуальной обратной связью, которую дает большой конструктор, что ваш класс становится слишком большим. Поэтому при использовании фасадов обращайте особое внимание на размер вашего класса, чтобы сфера его ответственности оставалась узкой.
При создании стороннего пакета, взаимодействующего с Laravel, лучше вводить контракты Laravel, а не использовать фасады. Поскольку пакеты создаются вне самого Laravel, у вас не будет доступа к помощникам по тестированию фасада Laravel.
Фасады Vs. Внедрение зависимости
Одним из основных преимуществ внедрения зависимостей является возможность обмена реализациями внедренного класса. Это полезно во время тестирования, поскольку вы можете ввести макет или заглушку и утверждать, что для заглушки были вызваны различные методы.
Как правило, было бы невозможно смутить или заглушить действительно статический метод класса. Тем не менее, поскольку фасады используют динамические методы для передачи вызовов методов для объектов, разрешенных из сервисного контейнера, мы фактически можем тестировать фасады так же, как мы проверяем экземпляр внедренного класса. Например, учитывая следующий маршрут:
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});
Мы можем написать следующий тест, чтобы убедиться, что метод был вызван с ожидаемым аргументом:Cache::get
use Illuminate\Support\Facades\Cache;
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$this->visit('/cache')
->see('value');
}
Фасады Vs. Вспомогательные функции
В дополнение к фасадам, Laravel включает в себя множество «вспомогательных» функций, которые могут выполнять общие задачи, такие как генерация представлений, запуск событий, диспетчеризация заданий или отправка HTTP-ответов. Многие из этих вспомогательных функций выполняют ту же функцию, что и соответствующий фасад. Например, этот вызов фасада и вспомогательный вызов эквивалентны:
return View::make('profile');
return view('profile');
Практически нет никакой разницы между фасадами и вспомогательными функциями. При использовании вспомогательных функций вы все равно можете тестировать их точно так же, как и соответствующий фасад. Например, учитывая следующий маршрут:
Route::get('/cache', function () {
return cache('key');
});
Под капотом cache
помощник собирается вызвать get
метод для класса, лежащего в основе Cache
фасада. Итак, хотя мы используем вспомогательную функцию, мы можем написать следующий тест, чтобы убедиться, что метод был вызван с ожидаемым аргументом:
use Illuminate\Support\Facades\Cache;
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$this->visit('/cache')
->see('value');
}
Как работают фасады
В приложении Laravel фасад - это класс, который обеспечивает доступ к объекту из контейнера. Техника, которая делает эту работу, находится в Facade
классе. Фасады Laravel и любые другие созданные вами фасады расширят базовый класс.Illuminate\Support\Facades\Facade
Facade
Базовый класс использует магический способ отложить вызовы с вашего фасада к объекту разрешен из контейнера. В приведенном ниже примере выполняется вызов кеш-системы Laravel. Взглянув на этот код, можно предположить, что статический метод вызывается в классе:__callStatic()
get
Cache
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @param int $id
* @return Response
*/
public function showProfile($id)
{
$user = Cache::get('user:'.$id);
return view('profile', ['user' => $user]);
}
}
Обратите внимание, что в верхней части файла мы «импортируем» Cache
фасад. Этот фасад служит прокси для доступа к базовой реализации интерфейса. Любые звонки, которые мы делаем с помощью фасада, будут переданы в базовый экземпляр службы кэширования Laravel.Illuminate\Contracts\Cache\Factory
Если мы посмотрим на этот класс, вы увидите, что нет статического метода :Illuminate\Support\Facades\Cache
get
class Cache extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor() { return 'cache'; }
}
Вместо этого Cache
фасад расширяет базовый Facade
класс и определяет метод . Задача этого метода - вернуть имя привязки контейнера службы. Когда пользователь ссылается на любой статический метод на фасаде, Laravel разрешает привязку из контейнера службы и запускает запрошенный метод (в данном случае ) для этого объекта.getFacadeAccessor()
Cache
cache
get
Фасады в реальном времени
Используя фасады в реальном времени, вы можете рассматривать любой класс в вашем приложении, как если бы это был фасад. Чтобы проиллюстрировать, как это можно использовать, давайте рассмотрим альтернативу. Например, предположим, что в нашей Podcast
модели есть publish
метод. Однако, чтобы опубликовать подкаст, нам нужно добавить Publisher
экземпляр:
<?php
namespace App;
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);
}
}
Внедрение реализации издателя в метод позволяет нам легко тестировать метод изолированно, так как мы можем издеваться над внедренным издателем. Однако это требует, чтобы мы всегда передавали экземпляр издателя каждый раз, когда мы вызываем publish
метод. Используя фасады в реальном времени, мы можем поддерживать ту же тестируемость, не требуя явной передачи Publisher
экземпляра. Чтобы создать фасад в реальном времени, добавьте префикс пространства имен импортируемого класса Facades
:
<?php
namespace App;
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\Podcast;
use Tests\TestCase;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;
class PodcastTest extends TestCase
{
use RefreshDatabase;
/**
* A test example.
*
* @return void
*/
public function test_podcast_can_be_published()
{
$podcast = factory(Podcast::class)->create();
Publisher::shouldReceive('publish')->once()->with($podcast);
$podcast->publish();
}
}
Ссылка на класс фасадов
Ниже вы найдете каждый фасад и его базовый класс. Это полезный инструмент для быстрого поиска документации 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 |
Lang | Illuminate\Translation\Translator | translator |
Log | Illuminate\Log\LogManager | log |
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 |
0 комментариев