git 95f9380c1e0ab62118ccaa49d2bc43a80b0b13c8
- Введение
- Описание
- Практическое использование
- Создание фасадов
- Фасады для тестирования
- Facade Class Reference
Фасады предоставляют «статический» интерфейс (Foo::bar()
) к классам, доступным в сервис-контейнере. Laravel поставляется
со множеством фасадов и вы, вероятно, использовали их, даже не подозревая об этом.
Иногда вам может понадобиться создать собственные фасады для вашего приложения и пакетов (packages), поэтому давайте изучим идею, разработку и использование этих классов.
Примечание: перед погружением в фасады настоятельно рекомендуется как можно детальнее изучить сервис-контейнер Laravel.
В контексте приложения на Laravel, фасад - это класс, который предоставляет доступ к объекту в контейнере. Весь этот механизм реализован
в классе Facade
. Фасады как Laravel, так и ваши собственные, наследуют этот базовый класс.
Ваш фасад должен определить единственный метод: getFacadeAccessor
. Его задача - определить, что вы хотите получить из контейнера.
Класс Facade
использует магический метод PHP __callStatic()
для перенаправления вызовов методов с вашего фасада на полученный объект.
Например, когда вы вызываете Cache::get()
, Laravel получает объект CacheManager
из сервис-контейнера и вызывает метод get
этого класса.
Другими словами, фасады Laravel предоставляют удобный синтаксис для использования сервис-контейнера в качестве сервис-локатора (service locator).
В примере ниже делается обращение к механизму кэширования Laravel. На первый взгляд может показаться, что метод get
принадлежит классу Cache
.
$value = Cache::get('key');
Однако, если вы посмотрите в исходный код класса Illuminate\Support\Facades\Cache
, то увидите, что он не содержит метода get
:
class Cache extends Facade {
/**
* Получить зарегистрированное имя компонента.
*
* @return string
*/
protected static function getFacadeAccessor() { return 'cache'; }
}
Класс Cache наследует класс Facade
и определяет метод getFacadeAccessor()
. Как вы помните, его задача - вернуть строковое имя (ключ)
привязки объекта в сервис-контейнере.
Когда вы обращаетесь к любому статическому методу фасада Cache
, Laravel получает объект cache
из сервис-контейнера и вызывает на нём требуемый метод
(в этом случае - get
).
Таким образом, вызов Cache::get
может быть записан так:
$value = $app->make('cache')->get('key');
Помните, если вы используете фасады в контроллерах с указанным пространством имён, вам нужно импортировать классы фасадов. Все фасады находятся в глобальном пространстве имён.
<?php namespace App\Http\Controllers;
use Cache;
class PhotosController extends Controller {
/**
* Get all of the application photos.
*
* @return Response
*/
public function index()
{
$photos = Cache::get('photos');
//
}
}
Создать фасад довольно просто. Вам нужны только три вещи:
- Биндинг (привязка) в сервис-контейнер.
- Класс-фасад.
- Настройка для псевдонима фасада.
Посмотрим на следующий пример. Здесь определён класс PaymentGateway\Payment
.
namespace PaymentGateway;
class Payment {
public function process()
{
//
}
}
Нам нужно, чтобы этот класс извлекался из сервис-контейнера, так что давайте добавим для него привязку (binding):
App::bind('payment', function()
{
return new \PaymentGateway\Payment;
});
Самое лучшее место для регистрации этой связки - новый сервис-провайдер который мы назовём
PaymentServiceProvider
и в котором мы создадим метод register
, содержащий код выше. После этого вы можете настроить Laravel для загрузки
этого провайдера в файле config/app.php
.
Дальше мы можем написать класс нашего фасада:
use Illuminate\Support\Facades\Facade;
class Payment extends Facade {
protected static function getFacadeAccessor() { return 'payment'; }
}
Наконец, по желанию можно добавить псевдоним (alias) для этого фасада в массив aliases
файла настроек config/app.php
- тогда мы сможем
вызывать метод process
на классе Payment
.
Payment::process();
В некоторых случаях классы в массиве aliases
не доступны из-за того, что PHP не загружает неизвестные классы в подсказках типов.
Если \ServiceWrapper\ApiTimeoutException
имеет псевдоним ApiTimeoutException
, то блок catch(ApiTimeoutException $e)
, помещённый в любое
пространство имён, кроме \ServiceWrapper
, никогда не «поймает» это исключение, даже если оно было возбуждено внутри него.
Аналогичная проблема возникает в классах, которые содержат подсказки типов на неизвестные (неопределённые) классы.
Единственное решение - не использовать псевдонимы и вместо них в начале каждого файла писать use
для ваших классов.
Юнит-тесты играют важную роль в том, почему фасады делают именно то, то они делают. На самом деле возможность тестирования - основная причина, по которой фасады вообще существуют. Эта тема подробнее раскрыта в соответствующем разделе документации - фасады-заглушки.
Ниже представлена таблица соответствий фасадов Laravel и классов, лежащих в их основе.