Может войдёшь?
Черновики Написать статью Профиль

Контракты

перевод документация 5.х

  1. 1. Введение
    1. 1.1. Контракты или фасады?
  2. 2. Когда использовать контракты
    1. 2.1. Слабая связанность
    2. 2.2. Упрощение кода
  3. 3. Как использовать контракты
  4. 4. Список контрактов
Этот перевод актуален для англоязычной документации на (ветка 5.3) , (ветка 5.2) , (ветка 5.1) и (ветка 5.0). Опечатка? Выдели и нажми Ctrl+Enter.

Введение

Контракты в Laravel — это набор интерфейсов, которые описывают основной функционал, предоставляемый фреймворком. Например, контракт Illuminate\Contracts\Queue\Queue определяет методы, необходимые для организации очередей, в то время как контракт Illuminate\Contracts\Mail\Mailer определяет методы, необходимые для отправки электронной почты.

Каждый контракт имеет свою реализацию во фреймворке. Например, Laravel предоставляет реализацию PHPQueue с различными драйверами и реализацию PHPMailer, использующую SwiftMailer.

Все контракты Laravel живут в своих собственных репозиториях GitHub. Эта ссылка ведёт на все доступные контракты, а также на один отдельный пакет, который может быть использован разработчиками пакетов.

Контракты или фасады?

Фасады Laravel и вспомогательные функции дают простой способ использования сервисов Laravel без необходимости типизирования и извлечения контрактов из сервис-контейнера. В большинстве случаев у каждого фасада есть эквивалентный контракт.

В отличие от фасадов, которые не требуют того, чтобы вы запрашивали их в конструкторе вашего класса, контракты позволяют вам определить конкретные зависимости для ваших классов. Некоторые разработчики предпочитают именно так явно определять свои зависимости, поэтому предпочитают использовать контракты, а другие разработчики наслаждаются удобством фасадов.

Для большинства приложений неважно, что вы выберете — фасады или контракты. Но если вы создаёте пакет, то вам надо использовать контракты, так как в этом случае их проще тестировать.

Когда использовать контракты

Это обсуждается повсюду, и большинство дискуссий сводятся к тому, что использование контрактов или фасадов — это дело вкуса или предпочтений вашей команды разработчиков. И те, и другие можно использовать для создания надёжных, проверенных Laravel-приложений. Пока вы сохраняете границы ответственности вашего класса узкими, вы сможете заметить всего несколько практических различий между использованием контрактов и фасадов.

Однако, у вас по-прежнему могут остаться некоторые вопросы о контрактах. Например, зачем вообще нужны интерфейсы? Разве их использование делает жизнь проще? Определим причины использования интерфейсов как следующие: это слабая связанность (loose coupling) и упрощение кода.

Слабая связанность

Но для начала рассмотрим код с сильной связанностью с реализацией кэша. Рассмотрите следующее:

PHP
<?php

namespace App\Orders;

class 
Repository {

  
/**
   * Экземпляр кэша.
   */
  
protected $cache;

  
/**
   * Создание нового экземпляра репозитория.
   *
   * @param  \SomePackage\Cache\Memcached  $cache
   * @return void
   */
  
public function __construct(\SomePackage\Cache\Memcached $cache)
  {
    
$this->cache $cache;
  }

  
/**
   * Получение заказа по ID.
   *
   * @param  int  $id
   * @return Order
   */
  
public function find($id)
  {
    if (
$this->cache->has($id))  {
      
//
    
}
  }

}

В этом классе код сильно связан с реализацией кэша, потому что мы зависим от конкретного класса Cache данного пакета. Если API этого пакета изменится, наш код должен также измениться.

Аналогично, если мы хотим заменить нашу базовую технологию кэша (Memcached) другой технологией (Redis), нам придётся вносить изменения в наш репозиторий. А наш репозиторий не должен задумываться о том, кто именно предоставляет данные или как он это делает.

Вместо такого подхода, мы можем улучшить наш код, добавив зависимость от простого интерфейса, которой не зависит от поставщика:

PHP
<?php

namespace App\Orders;

use 
Illuminate\Contracts\Cache\Repository as Cache;

class 
Repository
{
  
/**
  * Экземпляр кэша.
  */
  
protected $cache;

  
/**
   * Создание нового экземпляра репозитория.
   *
   * @param  Cache  $cache
   * @return void
   */
  
public function __construct(Cache $cache)
  {
    
$this->cache $cache;
  }

}

Теперь код не привязан к какому-либо определённому поставщику, и даже не привязан к Laravel. Контракт не содержит никакой конкретной реализации и никаких зависимостей. Вы можете легко написать свою реализацию любого контракта, что позволяет вам заменить реализацию работы с кэшем, не изменяя ни одной строчки вашего кода, работающего с кэшем.

Упрощение кода

Когда все сервисы Laravel аккуратно определены в простых интерфейсах, очень легко определить функциональность, предлагаемую данными сервисами. Фактически, контракты являются краткой документацией для функций Laravel.

Кроме того, когда в своём приложении вы внедряете в классы зависимости от простых интерфейсов, в вашем коде легче разобраться и его проще поддерживать. Вместо того, чтобы искать методы в большом и сложном классе, вы можете обратиться к простому и понятному интерфейсу.

Как использовать контракты

Как получить реализацию контракта? Это довольно просто. Множество типов классов в Laravel регистрируются в сервис-контейнере, включая контроллеры, слушатели событий, посредники, очереди и даже замыкания. Поэтому, чтобы получить реализацию контракта, вам достаточно указать тип интерфейса в конструкторе необходимого класса. Например, посмотрите на этот обработчик событий:

PHP
<?php

namespace App\Listeners;

use 
App\User;
use 
App\Events\OrderWasPlaced;
use 
Illuminate\Contracts\Redis\Database;

class 
CacheOrderInformation
{
  
/**
   * Реализация базы данных Redis.
   */
  
protected $redis;

  
/**
   * Создание нового экземпляра обработчика событий.
   *
   * @param  Database  $redis
   * @return void
   */
  
public function __construct(Database $redis)
  {
    
$this->redis $redis;
  }

  
/**
   * Обработка события.
   *
   * @param  OrderWasPlaced  $event
   * @return void
   */
  
public function handle(OrderWasPlaced $event)
  {
    
//
  
}
}

Когда будет получен слушатель события, сервис-контейнер прочитает указание типа в конструкторе класса и внедрит нужное значение. Узнать больше о регистрации в сервис-контейнере можно в документации.

Список контрактов

В этой таблице приведены ссылки на все контракты Laravel, а также эквивалентные им фасады:

Контракт Соответствующий фасад
Illuminate\Contracts\Auth\Factory для 5.2+
Illuminate\Contracts\Auth\Guard для 5.1-
Auth
Illuminate\Contracts\Auth\PasswordBrokerPassword
Illuminate\Contracts\Bus\DispatcherBus
Illuminate\Contracts\Broadcasting\Broadcaster 
Illuminate\Contracts\Cache\RepositoryCache
Illuminate\Contracts\Cache\FactoryCache::driver()
Illuminate\Contracts\Config\RepositoryConfig
Illuminate\Contracts\Container\ContainerApp
Illuminate\Contracts\Cookie\FactoryCookie
Illuminate\Contracts\Cookie\QueueingFactoryCookie::queue()
Illuminate\Contracts\Encryption\EncrypterCrypt
Illuminate\Contracts\Events\DispatcherEvent
Illuminate\Contracts\Filesystem\Cloud 
Illuminate\Contracts\Filesystem\FactoryFile
Illuminate\Contracts\Filesystem\FilesystemFile
Illuminate\Contracts\Foundation\ApplicationApp
Illuminate\Contracts\Hashing\HasherHash
Illuminate\Contracts\Logging\LogLog
Illuminate\Contracts\Mail\MailQueueMail::queue()
Illuminate\Contracts\Mail\MailerMail
Illuminate\Contracts\Queue\FactoryQueue::driver()
Illuminate\Contracts\Queue\QueueQueue
Illuminate\Contracts\Redis\DatabaseRedis
Illuminate\Contracts\Routing\RegistrarRoute
Illuminate\Contracts\Routing\ResponseFactoryResponse
Illuminate\Contracts\Routing\UrlGeneratorURL
Illuminate\Contracts\Support\Arrayable 
Illuminate\Contracts\Support\Jsonable 
Illuminate\Contracts\Support\Renderable 
Illuminate\Contracts\Validation\FactoryValidator::make()
Illuminate\Contracts\Validation\Validator 
Illuminate\Contracts\View\FactoryView::make()
Illuminate\Contracts\View\View 

Комментарии (2)

denisbondar

Кажется, тут немного с переводом ошиблись. Причем довольно эпично.
Low Coupling — это слабая связанность, а не связность. Можно перевести как слабая зависимость или слабая связь между классами (модулями).
А то у вас получилось наоборот.

Должна быть слабая связанность (зависимость) Low Coupling между классами (модулями)
И высокая внутренняя связность High Cohesion внутри класса (модуля)

Proger_XP

Верно, в переводе ошибка. Спасибо за сообщение.

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.