Я работаю над веб-приложением с Yii2 и PHP и сталкиваюсь с типичной ситуацией множественного наследования.
У меня есть занятия A
а также B
продлить Yii2 ActiveRecord
класс, так как они представляют реляционные данные, хранящиеся в БД. Но тогда у меня есть класс C, который не расширяется (и не должен) ActiveRecord
но разделяет общее поведение и переменные-члены с A
а также B
, Другими словами, три класса искренне имеют общие отношения «есть» с сущностью реального мира, но только A
а также B
хранятся в БД.
До сих пор у меня все получалось, используя черты:
abstract class AbstractMotherClass extends ActiveRecord {
use MyTrait;
}
class A extends AbstractMotherClass {}
class B extends AbstractMotherClass {}
class C {
use MyTrait;
}
trait MyTrait {
public $someVariableInherentToAllThreeClasses;
public function someMethodInherentToAllThreeClasses() {
// do something
}
}
Тогда у меня есть метод, который может принять любой из трех классов (A
, B
или же C
) и работать с ним. До сих пор мне оставалось только бросить A
или же B
на это, так что я просто написал
public fonction someMethod(AbstractMotherClass $entity) {}
чтобы я мог получить подсказки типа и другие вещи в моей IDE. Но теперь я должен пройти C
а также приложение вылетает, так как метод не получает ожидаемого AbstractMotherClass
экземпляр, если я позвоню someMethod(new C());
, Чтобы решить это, мне нужен общий класс, который все A
, B
, А ТАКЖЕ C
может расширяться, чтобы я мог напечатать подсказку этого класса в моем методе. Но это было бы множественное наследование, так как A
а также B
должен также продлить ActiveRecord
но C
не может.
Я обнаружил множество проблем множественного наследования, но все они были решены путем изменения структуры объекта, разделения обязанностей, использования композиции вместо наследования и так далее. Мне не удалось применить эти решения здесь, потому что они не казались ни подходящими, ни практичными, но я могу ошибаться.
Каков был бы лучший способ сделать это?
Также, если у кого-то есть лучшее предложение для заголовка, я был бы рад изменить его (я не смог найти хорошего).
Как отметил и Грег Шмидт, вы можете использовать интерфейсы
class ActiveRecord {
}
interface SameInterface {
public function someMethodInherentToAllThreeClasses();
}
abstract class AbstractMotherClass extends ActiveRecord implements SameInterface{
use MyTrait;
}
class A extends AbstractMotherClass {}
class B extends AbstractMotherClass {}
class C implements SameInterface{
use MyTrait;
}
trait MyTrait {
public $someVariableInherentToAllThreeClasses;
public function someMethodInherentToAllThreeClasses() {
return 'bar';
}
}
function foo(SameInterface $o) {
return $o->someMethodInherentToAllThreeClasses().PHP_EOL;
}
echo foo(new C());
Конечно, вы должны скопировать и вставить в интерфейс someMethodInherentToAllThreeClasses. Интерфейсы обычно используются для решения некоторой проблемы множественного наследования.
Других решений пока нет …