Наследование классов – механизм, позволяющий создавать классы (говорят подклассы) на основе других классов (называемых базовыми или суперклассами). Подклассы в таком случае "наследуют" структуру базовых классов, то есть получают возможность использовать всё, что определено в базовом классе.
Механизм наследования – сложная система, со множеством элементов, дополнительных сущностей и особенностей поведения. Поэтому изучаться он будет в несколько приёмов, на протяжении всего курса.
Рассмотрим наследование на примере структуры HTML. Каждый тег в HTML по своему уникален. С другой стороны, все они имеют общие атрибуты и некоторые другие характеристики. Попробуем отобразить это с помощью иерархии классов.
<?php
// Базовый класс для всех тегов. Умеет работать с атрибутами.
class HTMLElement
{
public $body;
public $attributes = [];
public function __construct($attributes = [])
{
$this->attributes = $attributes;
}
public function setAttribute(string $key, $value)
{
$this->attributes[$key] = $value;
}
public function getAttribute(string $key)
{
return $this->attributes[$key];
}
public function getTextContent()
{
return $this->body;
}
public function setTextContent($body)
{
$this->body = $body;
}
protected function stringifyAttributes()
{
// build: key="value" key2="value2"
}
}
Конкретные элементы, представленные тегами в HTML, наследуются от этого класса:
<?php
// Anchor – это ссылка. Класс HTMLAnchorElement описывает тег "a".
// Наследование выполняется через ключевое слово extends
class HTMLAnchorElement extends HTMLElement
{
public function __toString()
{
// Родительский метод
$attrLine = $this->stringifyAttributes();
// Родительский метод
$body = $this->getTextContent();
return "<a{$attrLine}>{$body}</a>";
}
}
Наследование записывается так: A extends B
. Эта запись означает, что класс A наследует класс B. Теперь посмотрим, как работает наследование:
<?php
// Конструктор родителя
$anchor = new HTMLAnchorElement(['href' => 'https://ru.hexlet.io']);
$anchor->setTextContent('Hexlet');
echo "Anchor: {$anchor}"; // __toString вызывается автоматически
// Anchor: <a href="https://ru.hexlet.io">Hexlet</a>
Внутри HTMLAnchorElement нет определения конструктора, но благодаря наследованию, этот класс имеет доступ ко всем публичным методам и свойствам суперкласса. PHP вызывает их автоматически при обращении к ним. В свою очередь, внутри __toString()
вызываются методы, которых нет в текущих классах, поэтому они также берутся из родительского класса.
Цепочка наследования
В отличие от интерфейсов, наследование классов в PHP – одиночное. Другими словами, наследоваться можно только от одного класса. Точно так же как и в Java. Множественное наследование в этих языках было убрано специально, из-за его высокой сложности и проблем, которые оно добавляет (например, коллизии методов и свойств). С другой стороны, сама по себе цепочка наследования может быть сколь угодно глубокой:
<?php
class D {}
class C extends D {}
class B extends C {}
class A extends B {}
Оператор проверки типа
Оператор instanceof
учитывает классы из цепочки наследования:
<?php
$anchor = new HTMLAnchorElement();
if ($anchor instanceof HTMLElement) {
echo '!!!';
}
// !!!
Если нужно проверить точный класс, то это можно сделать по-другому:
<?php
$anchor = new HTMLAnchorElement();
get_class($anchor); // 'HTMLAnchorElement'
Не забывайте, что подобные проверки закрывают возможность использовать полиморфизм. Иногда без них не обойтись, но в подавляющем большинстве случаев лучше завязываться на интерфейс объекта.
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.