Я реализовал шаблон репозитория в своем проекте без особых проблем. Чтобы не повторяться, я реализовал 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 для реализации репозитория, что позволило бы мне использовать универсальный тип в сигнатурах метода.
Можно ли заставить это работать так, чтобы:
?User
за UserRepositoryInterface
а также ?Product
за ProductRepositoryInterface
)?На мой взгляд, у меня есть несколько вариантов:
?Model
которые расширяют все мои модели.Я считаю, что в организации этих репозиториев есть небольшие недостатки дизайна, без которых проблема не исчезнет.
Поэтому я добавил тип возврата «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 относится к модели слой, в котором мы можем найти лиц, услуг, картографов. Больше чтения Вот.
Других решений пока нет …