Инвариант для ограничения переопределения функций в Hack PHP

У меня есть базовый класс в PHP Hack с функцией:

// This method is used to return just one Apple Type
protected static function Apple(): AppleType {
    return AppleType;
}

Теперь у меня есть два типа классов: один использует базовую черту, другой — нет.

Черта имеет следующую функцию:

// This method is used to return more than one Apple Type
protected static function Apples(): keyset[AppleType] {
    return keyset[AppleType];
}

Дочерние классы, которые не используют эту черту, могут переопределить метод базового класса Apple(). Но классы, которые используют трейт, должны переопределять Apples(), а не Apple().

Теперь я хочу предоставить инвариантное исключение:

Что-то типа:

invariant(Apple() is not overridden in this class, 'Class must override Apples() and not Apple()');

то есть инвариант, обеспечивающий принудительное выполнение того, что класс, использующий трейт, не должен иметь возможность переопределять Apple() базового класса и выдает исключение во время выполнения.

Пожалуйста, помогите мне написать этот инвариант. Я пробовал много вещей, но как-то это не работает правильно.


person ADT    schedule 18.07.2020    source источник
comment
Черты не должны создавать требования, если они не используются. Вы можете заставить подклассы реализовать интерфейс с подписью apples() через требования к трейту и интерфейсу, но только если методы в этом трейте используют метод apples(). Должен ли apples() быть абстрактным в вашем примере? Можете ли вы рассказать больше о том, почему вы хотите применить этот инвариант?   -  person concat    schedule 19.07.2020


Ответы (1)


Вы можете определить класс с помощью метода final и потребовать, чтобы пользователи признаков расширяли этот класс.

enum AppleType: int {
  Fresh = 1;
  Stale = 2;
}

class Overridable {
  protected static function Apple(): AppleType {
    return AppleType::Fresh;
  }
}

class MustUseApples extends Overridable {
  <<__Override>>
  final protected static function Apple(): AppleType {
    return parent::Apple();
  }
}

trait MyTrait {
  require extends MustUseApples;

  protected static function Apples(): keyset<AppleType> {
    return keyset[AppleType::Stale];
  }
}

Однако, если вы хотите потребовать, чтобы трейт-пользователи предоставляли реализацию Apples, вам, вероятно, следует сделать его абстрактным методом для MustUseApples.

person Wilfred Hughes    schedule 20.07.2020