Как стать автором
Обновить

Множественное наследование в PHP на собеседовании

Уровень сложностиСредний

Стандартным вопросом на PHP собеседованиях выступает вопрос про наследование, может ли класс наследовать нескольким классам или нет. На поверхности, конечно лежит ответ – «нет не может, класс всегда наследует только одному родителю». Далее обычно идет что-то «но если сильно нужно, то можно, так как есть трейты» и на этом все кончается. Как правило, и соискатель и интервьюер множественное наследование в деле не испытывали, и обоим просто добавить тут нечего.

А добавит есть что... Дело в том, что трейт - это механизм повторного использования кода. И этот механизм никак не влияет на типизацию, а без типизации наследование не наследование!

В случае использования обычного наследования мы имеем

class ParentClass {}
class ChildClass extends ParentClass {}

$testObject = new ChildClass();

var_dump(is_a(testObject, ChildClass::class)); // Выведет TRUE
var_dump(is_a(testObject, ParentClass::class)); // Выведет TRUE

В случае "наследования" с помощью трейтов, такое уже не прокатит, is_a(), is_subclass_of() и instanceof - никак не отреагируют на используемый трейт. И это проблема, так как множественное наследование - это не только повторное использование кода, но и возможность использовать объекты класса потомка там, где могли использоваться объекты класса-родителя...

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

Таким образом, для реализации множественного наследования в PHP нужно одновременно использовать трейты и интерфейсы

Благодаря интерфейсам:

  • Решена проблема типизации

  • Использование констант

Благодаря трейтам:

  • Повторное использование методов и свойств

  • Использование констант (начиная с PHP 8.2)

В качестве примера - класс "русалка", наследующий "рыб" и "человека", и класс "морской дом", который при создании получает "владельца". Владельцем "морского дома" может быть только рыба.

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

// Интерфейс "рыба"
interface FishInterface {}
// Интерфейс "человек"
interface HumanInterface {}

// трейт "рыба"
trait FishTrait {}
// трейт "человек"
trait HumanTrait {}

// класс "русалка"
class Mermaid implements FishInterface, HumanInterface
{
  use FishTrait;
  use HumanTrait;
}

// * * *

// Класс "морской дом"
// Владельца может быть "рыба", "русалка", но не "человек"
class SeaHome
{
  public function __construct(public FishInterface $owner) {}
}

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.