Введение в Laravel 5Сервис-контейнер в Laravel
Сервис-контейнерсредство для управлениязависимостями классов
ивнедрения зависимостей.
Внедрение зависимостей (DI)конструктор или метод-сеттер
namespace App\Jobs;
class PurchasePodcast implements SelfHandling{ protected $mailer;
public function __construct(Mailer $mailer) { $this->mailer = $mailer; }
сервис внедрёнможем легко подменить его с другой реализацией
Можно легко создать «mock» или фиктивную реализацию при тестировании приложения
Связывание
Все привязки сервис-контейнеров будут зарегистрированы в сервис-провайдерах
Сервис-провайдеры - основа «первоначальной загрузки» Laravel
Приложение и все базовые сервисы загружаются через сервис-провайдеры
«Первоначальная загрузка»регистрация таких вещей как:
● привязки сервис-контейнера● слушатели событий (event listener)● посредники (middleware)● маршруты (routes)
Сервис-провайдерыцентральное место для настройки приложения
Если открытьconfig/app.php
поставляемый с Laravelто увидим… (deferred)
'providers' => [
/* * Laravel Framework Service Providers... */ Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Bus\BusServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class, Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
Если классы не зависят от интерфейсовне надо связывать их в контейнере
Не нужно объяснять контейнеру, как создавать эти объектыСервисы отражения PHP (Reflection)
В сервис-провайдере всегда есть доступ к контейнеру через переменную экземпляра $this->app
Привязка методом bind()
Первый аргумент имя класса или интерфейсаВторой замыкание (Closure), которое возвращает
экземпляр класса
$this->app->bind('HelpSpot\API', function ($app) { return new HelpSpot\API($app['HttpClient']);});
Получаем сам контейнер в виде аргумента «резолвера»Затем можно использовать контейнер, чтобы получать под-
зависимости создаваемого объекта
Связывание синглтона
singleton()привязывает класс или интерфейс к контейнеру
должен быть создан только один раз
$this->app->singleton('FooBar', function ($app) { return new FooBar($app['SomethingElse']);});
Связывание существующего экземпляра класса с контейнером
instance()Привязка существующего экземпляра к контейнеру
экземпляр будет всегда возвращаться при последующих обращениях к контейнеру
$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar);
Связывание интерфейса с реализацией
<?phpnamespace App\Handlers\Commands;
use App\Commands\CreateOrder;use Pusher\Client as PusherClient;
class CreateOrderHandler {
/** * Экземпляр клиента Pusher SDK. */ protected $pusher;
public function __construct(PusherClient $pusher) { $this->pusher = $pusher; }
<?phpnamespace App\Contracts;
interface EventPusher {
/** * Push a new event to all clients. * * @param string $event * @param array $data * @return void */ public function push($event, array $data);
}
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
<?phpnamespace App\Handlers\Commands;
use App\Contracts\EventPusher;
class CreateOrderHandler {
/** * Экземпляр клиента Pusher SDK. */ protected $pusher;
/** * Создание нового экземпляра класса. * * @param EventPusher $pusher * @return void */ public function __construct(EventPusher $pusher) { $this->pusher = $pusher; }
Контекстное связывание
$this->app->when('App\Handlers\Commands\CreateOrderHandler') ->needs('App\Contracts\EventPusher') ->give('App\Services\PubNubEventPusher');
$this->app->when('App\Handlers\Commands\CreateOrderHandler') ->needs('App\Contracts\EventPusher') ->give(function () { // Извлечение зависимости... });
Получение из контейнера
$fooBar = $this->app->make('FooBar');
$fooBar = $this->app['FooBar']; // ArrayAccess
public function __construct(EventPusher $pusher)
Варианты
События контейнера
$this->app->resolving(function ($object, $app) { // Вызывается при извлечении объекта любого типа...});
$this->app->resolving(FooBar::class, function (FooBar $fooBar, $app) { // Вызывается при извлечении объекта типа "FooBar"...});