oop — PHP 7 возвращает тип наследования

Я реализовал шаблон репозитория в своем проекте без особых проблем. Чтобы не повторяться, я реализовал abstract класс репозитория, который расширяет все мои репозитории. Каждый репозиторий имеет свой interface что он должен реализовать.

У меня есть код, подобный следующему, который отлично работает:

class Model {}

class User extends Model {}

abstract class AbstractRepository
{
protected $model;

public function find($id)
{
$class = $this->model;

return new $class();
}
}

interface UserRepositoryInterface
{
public function find($id);
}

class UserRepository extends AbstractRepository implements UserRepositoryInterface
{
protected $model = User::class;
}

Я хочу начать использовать декларации возвращаемого типа в моем коде, обновившись до PHP 7.1. Поэтому я добавил ?Model тип возврата к find метод в моем AbstractRepository и ?User тип возврата к UserRepositoryInterface,

class Model {}

class User extends Model {}

abstract class AbstractRepository
{
protected $model;

public function find($id): ?Model
{
$class = $this->model;

return new $class();
}
}

interface UserRepositoryInterface
{
public function find($id): ?User;
}

class UserRepository extends AbstractRepository implements UserRepositoryInterface
{
protected $model = User::class;
}

Теперь PHP жалуется, что декларации несовместимы, что я вроде ожидал.

Неустранимая ошибка: объявление AbstractRepository :: find ($ id) должно быть совместимо с AbstractRepositoryInterface :: find ($ id):? Модель в /Users/jonathon/Desktop/test.php в строке 21

На другом языке, таком как Java, я бы подумал об использовании Generics для реализации репозитория, что позволило бы мне использовать универсальный тип в сигнатурах метода.

Можно ли заставить это работать так, чтобы:

  • У меня есть интерфейс и реализация для каждого хранилища
  • У меня есть абстрактный класс, который расширяется каждым из моих репозиториев, который выполняет большую часть работы.
  • Я могу продолжать использовать декларации возвращаемого типа в PHP 7, указав разные типы возвращаемых данных для каждого отдельного репозитория (например, ?User за UserRepositoryInterface а также ?Product за ProductRepositoryInterface)?

На мой взгляд, у меня есть несколько вариантов:

  • Не беспокойтесь об использовании типов возврата.
  • Измените все декларации возвращаемого типа на ?Model которые расширяют все мои модели.
  • Повторяю себя, избавляясь от абстрактного класса

1

Решение

Я считаю, что в организации этих репозиториев есть небольшие недостатки дизайна, без которых проблема не исчезнет.

Поэтому я добавил тип возврата «Model» в метод поиска в моем AbstractRepository и тип возврата «User» в UserRepositoryInterface.

Почему смена типа? Пользователь должен быть моделью, просто используйте модель в качестве подсказки типа.

Чтобы не повторяться, я реализовал абстрактный класс репозитория, который расширяет все мои репозитории. Каждый репозиторий имеет свой собственный интерфейс, который он должен реализовать.

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

interface Repository
{
public function find($id): Model;
}

Что абстрактное хранилище реализует:

abstract class AbstractRepository implements Repository
{
protected $model;

public function find($id): Model
{
$class = $this->model;

return new $class();
}
}

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

class UserRepository extends AbstractRepository
{
public function __construct()
{
$this->model = User::class;
}
}

Больше никаких проблем с подсказками типов.


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

interface Repository
{
public function find($id): Model;
}class UserRepository implements Repository
{
public function find($id): Model
{
return new User();
}
}

Последняя хитрость: модель — плохое имя. Это может быть сущность. Модель в MVC относится к модели слой, в котором мы можем найти лиц, услуг, картографов. Больше чтения Вот.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]