репозиторий laravel — зачем нужно вызывать интерфейс вместо прямого вызова файла репозитория?

#php #laravel #interface #repository

#php #laravel #интерфейс #репозиторий

Вопрос:

Я читал о шаблоне репозитория.Итак, я создал UserRepositoryInterface.php файл

 namespace AppInterfaces;

use PrettusRepositoryContractsRepositoryInterface;

interface UserInterface extends RepositoryInterface
{
    // Code
}
  

Затем я создал UserRepository.php :

 <?php

namespace AppRepositories;

use PrettusRepositoryEloquentBaseRepository;
use AppInterfacesUserInterface;

class UserRepository extends BaseRepository implements UserInterface
{
    public function model()
    {
        return User::class;
    }
}
  

Наконец, я привязываю интерфейс к классу в RepositoryServiceProvider.php

     public function boot()
    {
        $this->app->bind(UserInteface::class, UserRepository::class);
    }
  

Когда я вводю репозиторий в класс, мне интересно, что я должен вводить с UserRepository помощью or UserInterface . Я читал, что UserInterface это должно быть введено, но я не понимаю, почему мы не просто используем UserRepository , это может быть быстрее, не так ли?
Кто-нибудь помогает?

Спасибо.

Ответ №1:

Весь смысл внедрения интерфейса вместо конкретного класса в том, чтобы упростить change/extend/maintenance/test его.

Теперь, в вашем случае, вы внедрили UserRepositoryInterface , скажем, какой-то метод контроллера или конструктор. Но UserRepository class по-прежнему тесно связан с кодом Eloquent (поскольку он расширяет класс Eloquent).

Теперь представьте, что вы получаете пользователей от другого поставщика / источника (возможно, от третьей стороны через вызов API). Этот код вы можете установить в отдельном классе AppRepositoriesApiCallUserRepository (например).

Вы также должны установить ApiCallUserRepository (вновь созданный класс) для реализации AppInterfacesUserInterface .

Когда у вас есть все это, единственное изменение, которое вы должны внести, это изменить поставщика или, другими словами, вам просто нужно указать приложению, какой конкретный класс использовать, когда интерфейс был введен зависимо. Кроме того, это означает, что одна и та же структура данных должна предоставляться обоими конкретными классами (поставщиками репозиториев) классу, который использует репозиторий (т.Е. Метод контроллера), или, по крайней мере, получающий класс / код данных должен ожидать предоставления структуры, будь то коллекция Eloquent или какой-либо другой тип коллекции.

Таким образом, у вас есть хорошо настроенный сервис, который, например, получает пользователей. И вы можете легко выбрать, от какого провайдера вы хотите получить пользователей.

Это еще не все: во время выполнения (т. Е. При выполнении запроса) Вы можете установить соответствующий конкретный класс или создать дополнительный код, соответствующий любым произвольным правилам. Проверьте контейнер службы Laravel when()->needs()->give() , но также я настоятельно рекомендую вам снова просмотреть полные (страничные) документы.

Также не ограничивайте себя, а просмотрите другие общие и конкретные статьи о DI:

php-di

designpatternsphp

Компонент Symfony DependencyInjection

laminas-di

Возможно, все это кажется накладными расходами, но на самом деле это хорошая отправная позиция для расширения приложения хорошим, стандартным, поддерживаемым и тестируемым способом.

Комментарии:

1. Извините за недавний ответ и спасибо за ваш ответ. Согласно вашему ответу, я могу понять, что я вводил интерфейс вместо класса для целей тестирования и был проще для изменения класса. Это правильно? И что касается времени выполнения, я прочитал документ laravel Container Service , но я все еще не понимаю, как Contextual Binding это связано со временем выполнения. Я что-то пропустил?

2. Не только для целей тестирования. Но код, написанный таким образом, даст вам больше свободы в тестировании, правильно. Поскольку вы можете использовать разные классы в. среда тестирования. (т. Е. Вы можете легко изменить конфигурацию БД или конфигурацию кэша в тестах). Пример в документах довольно понятен. Также проверьте страницу контрактов (которая представляет собой PHP-интерфейсы и внедрение зависимостей на странице интерфейсов). Чтобы контекстная привязка работала на месте, вам нужно передать определенный интерфейс / контракт (который был привязан в классе Provider) конструктору контроллера (или любому классу, где он должен использоваться).

3. полностью понимаю с вашей ссылочной ссылкой. Спасибо.

Ответ №2:

Честно говоря, использование репозиториев с Eloquent просто тратит время. При ActiveRecord этом вся логика хранения и получения данных уже реализована в моделях. Вам просто НЕ нужен другой класс и интерфейс для вызова User::all() . Это просто хороший пример чрезмерной инженерии.