#php #interface #phpstorm #abstract #phpdoc
#php #интерфейс #phpstorm #аннотация #phpdoc
Вопрос:
Представьте себе следующий абстрактный интерфейс
interface IDomainRepository {
/**
* Finds a Domain Object by the Id
*
* @param int $id the id of the object
*
* @return IDomainObject the domain object
*/
public function findById($id);
//More than that method...
}
А теперь конкретный интерфейс, который простирается от IDomainRepository
interface IUserRepository extends IDomainRepository {
//More than only extending...
}
Если я вызываю что-то подобное, я хочу ввести подсказку без дополнительных комментариев здесь (потому что я использую это очень часто).
function foo(IUserRepository $repo) {
$user = $repo->findById(42)
//Typehint User without @var User $user
}
В настоящее время я делаю это так:
/**
* Interface IUserRepository
* @method User findById($id)
*/
interface IUserRepository extends {
}
Но параметр «@method» предназначен для скрытых магических методов. Так что это кажется неправильным. Есть ли лучшее доступное решение?
Должен ли я иметь не базовый интерфейс, а только конкретный (что означает копирование и вставку около 20 сигнатур методов?
Комментарии:
1. Это, по-видимому, является ограничением анализа и индексации иерархии IDE, когда она генерирует свою объектную модель. Базового наследования в коде должно быть достаточно, чтобы предоставить вам автозаполнение, которое вы ищете. Использование
@method
— это действительно только хак, чтобы заставить IDE вести себя так, как вам нужно. Нет «лучшего» или «правильного» способа сделать это … IDE — это то, что подводит вас здесь, IMO.
Ответ №1:
Поскольку в PHP пока нет намека на возвращаемый тип, в большинстве случаев все зависит от предпочтений, в зависимости от используемой IDE может не быть разницы в использовании @method
тега или docblock для объявления дополнительного метода, поэтому….
Обратите внимание, что вам не обязательно перемещать методы (и вы, скорее всего, не хотите этого делать, поскольку это сделало бы реализации IDomainRepository
не требующими findById()
метода), но вы можете просто переопределить / перезаписать их в своих расширяющихся интерфейсах, когда это необходимо, и предоставить соответствующий docblock, как показано @Deele:
interface IUserRepository extends IDomainRepository {
/**
* Finds a User by Id
*
* @param int $id the id of the object
*
* @return IUserRepository the User object
*/
public function findById($id);
}
Лично я бы счел, что более чистый подход по сравнению с использованием @method
, поскольку он делает более понятным, как findById()
должна вести себя конкретная реализация (просто взглянув на код объявления метода), и что ожидается, что он будет отличаться от базового интерфейса.
С другой стороны, однажды это также может быть «совместимо» с ковариантным намеком на возвращаемый тип, предложенным в PHP RFC: объявления возвращаемого типа:
// Covariant return-type:
interface Collection {
function map(callable $fn): Collection;
}
interface Set extends Collection {
function map(callable $fn): Set;
}
Ответ №2:
AFAIK, это невозможно сделать, потому что такая глубина не встроена в код PHPDoc.
Единственный способ, который я могу придумать, чтобы сохранить строки, — это повторить тот же findById()
метод внутри вашего User
класса и заставить его просто вызвать родительский метод findById()
и добавить комментарий с измененным @return
следующим образом
interface IUserRepository extends IDomainRepository {
/**
* @see IDomainRepository::findById()
*
* @param int $id the id of the object
*
* @return IUserRepository the User object
*/
public function findById($id) {
return parent::findById($id);
}
}
PS: findById()
в моем понимании логика ООП должна быть статической функцией.
Комментарии:
1. Причина, по которой он нестатичен
__construct(IUserRepository $userRepository)
, связана с дизайном, управляемым доменом. Я что-то не так понял? Предоставленный вами код не будет работать (это интерфейс, а не абстрактный класс), но говорит мне, что, возможно, мне следует переместитьfindBy*
методы в конечный интерфейс вместо базового интерфейса? Не уверен, что это лучше, чем@method User findById($id)
нотация, поскольку php doc не будет выполняться вместо кода php. Спасибо.
Ответ №3:
У меня похожая проблема, может static
быть, или $this
как возвращаемый тип может быть чем-то для вас.
Идея, лежащая в основе, относится к поздним статическим привязкам
interface IDomainRepository
{
/**
* @param int $id the id of the object
*
* @return static the domain object
*/
public function findById($id);
}
interface IUserRepository extends IDomainRepository
{
/**
* @param string $name
*
* @return static
*/
public function findUserByName($name);
}
function foo(IUserRepository $repo)
{
$user = $repo->findById(42);
$user->find... // suggestions by PHPStorm: findById and findUserByName
}
Комментарии:
1. Спасибо за ваши усилия. Я пытаюсь
$user
указать тип какUser
, а не какUserRepository
, который уже задан через параметр.2. Итак, что-то вроде Generic
IUserRepository extends IDomainRepository<User>
на других языках