0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Устранение дублирования кода - не единственная задача наследования классов. Иногда оно применяется для изменения существующего поведения базового класса.</p>
1
<p>Устранение дублирования кода - не единственная задача наследования классов. Иногда оно применяется для изменения существующего поведения базового класса.</p>
2
<p>Тег <select> в DOM представлен классом<em>HTMLSelectElement</em>. У него есть дополнительные методы, которые нужны для работы со списком элементов. Один из таких методов: item(index). С его помощью можно извлекать конкретный вариант из списка.</p>
2
<p>Тег <select> в DOM представлен классом<em>HTMLSelectElement</em>. У него есть дополнительные методы, которые нужны для работы со списком элементов. Один из таких методов: item(index). С его помощью можно извлекать конкретный вариант из списка.</p>
3
<p>Представим себе, что нам нужно часто обращаться к элементам этого списка с конца. Для этого постоянно придётся выполнять подобный код:</p>
3
<p>Представим себе, что нам нужно часто обращаться к элементам этого списка с конца. Для этого постоянно придётся выполнять подобный код:</p>
4
<p>В этом коде нет ничего криминального, но можно лучше. Один из возможных вариантов решения этой задачи состоит в том, чтобы расширить поведение метода и научить его работать с отрицательными числами. Возможность обращаться к индексам в обратном порядке - распространённая практика во многих языках.</p>
4
<p>В этом коде нет ничего криминального, но можно лучше. Один из возможных вариантов решения этой задачи состоит в том, чтобы расширить поведение метода и научить его работать с отрицательными числами. Возможность обращаться к индексам в обратном порядке - распространённая практика во многих языках.</p>
5
<p>Как это сделать? Наследование даёт возможность<strong>переопределять</strong>методы суперклассов. Посмотрите на пример:</p>
5
<p>Как это сделать? Наследование даёт возможность<strong>переопределять</strong>методы суперклассов. Посмотрите на пример:</p>
6
<p>Выше создан подкласс<em>HTMLCustomSelectElement</em>, который<strong>переопределяет</strong>метод item($index). Переопределение означает, что в подклассе создается метод с тем же именем, что и в родительском классе. Наш новый метод выполняет дополнительную работу по вычислению индекса, но ему все ещё нужен исходный метод item($index), для выборки нужного элемента. Для этого применяется специальный синтаксис, который указывает явно что нужно взять метод из родительского класса: parent::item($realIndex).</p>
6
<p>Выше создан подкласс<em>HTMLCustomSelectElement</em>, который<strong>переопределяет</strong>метод item($index). Переопределение означает, что в подклассе создается метод с тем же именем, что и в родительском классе. Наш новый метод выполняет дополнительную работу по вычислению индекса, но ему все ещё нужен исходный метод item($index), для выборки нужного элемента. Для этого применяется специальный синтаксис, который указывает явно что нужно взять метод из родительского класса: parent::item($realIndex).</p>
7
<p>Почему понадобился специальный синтаксис? Представьте, что вместо него там был бы такой код:</p>
7
<p>Почему понадобился специальный синтаксис? Представьте, что вместо него там был бы такой код:</p>
8
<p>Какой в этом случае метод item нужно брать - в определении которого мы находимся прямо сейчас или родительский? Наследование так устроено, что всегда выбирается тот метод, который находится ближе в цепочке наследования. Поэтому вызов через $this породит рекурсию, но родительский метод никогда не будет вызван.</p>
8
<p>Какой в этом случае метод item нужно брать - в определении которого мы находимся прямо сейчас или родительский? Наследование так устроено, что всегда выбирается тот метод, который находится ближе в цепочке наследования. Поэтому вызов через $this породит рекурсию, но родительский метод никогда не будет вызван.</p>
9
<p>По этой же причине, снаружи объекта невозможно вызвать методы, которые были переопределены в наследниках:</p>
9
<p>По этой же причине, снаружи объекта невозможно вызвать методы, которые были переопределены в наследниках:</p>
10
<p>Методы, как и свойства имеют модификаторы доступа. Причём они работают идентично: публичные методы доступны для всех, приватные только для текущего класса, а защищённые доступны всем наследникам как для вызова, так и переопределения.</p>
10
<p>Методы, как и свойства имеют модификаторы доступа. Причём они работают идентично: публичные методы доступны для всех, приватные только для текущего класса, а защищённые доступны всем наследникам как для вызова, так и переопределения.</p>
11
<p>Переопределение не ограничивается одним уровнем наследования. Любой переопределённый метод можно снова переопределить в наследниках текущего класса. Главное соблюдать два условия:</p>
11
<p>Переопределение не ограничивается одним уровнем наследования. Любой переопределённый метод можно снова переопределить в наследниках текущего класса. Главное соблюдать два условия:</p>
12
<ul><li>У обоих методов должны совпадать имена</li>
12
<ul><li>У обоих методов должны совпадать имена</li>
13
<li>Они должны иметь одинаковое количество обязательных аргументов</li>
13
<li>Они должны иметь одинаковое количество обязательных аргументов</li>
14
</ul><h2>Использование наследников</h2>
14
</ul><h2>Использование наследников</h2>
15
<p>Создать класс-наследник и начать его использовать - это две большие разницы. В ситуациях, где эти классы создаются вами, всё просто - достаточно заменить вызовы старого класса на новый, но если объекты этого класса создаются чужим кодом, то задача усложняется. Для подмены такого класса, от чужого кода требуется поддержка полиморфного поведения.</p>
15
<p>Создать класс-наследник и начать его использовать - это две большие разницы. В ситуациях, где эти классы создаются вами, всё просто - достаточно заменить вызовы старого класса на новый, но если объекты этого класса создаются чужим кодом, то задача усложняется. Для подмены такого класса, от чужого кода требуется поддержка полиморфного поведения.</p>
16
<p>Например, при работе с DOM, объекты этих классов иногда порождаются самим программистом, а иногда системой. Например:</p>
16
<p>Например, при работе с DOM, объекты этих классов иногда порождаются самим программистом, а иногда системой. Например:</p>
17
<p>Можно ли подменить класс в примере с querySelector? Зависит от реализации библиотеки по работе с DOM. В тех библиотеках, что мне известны, это сделать невозможно. Это значит, что единственный выход использовать собственный класс - это конвертировать вернувшийся объект в объект нужного нам класса. Стоит ли оно того? Почти наверняка, что нет.</p>
17
<p>Можно ли подменить класс в примере с querySelector? Зависит от реализации библиотеки по работе с DOM. В тех библиотеках, что мне известны, это сделать невозможно. Это значит, что единственный выход использовать собственный класс - это конвертировать вернувшийся объект в объект нужного нам класса. Стоит ли оно того? Почти наверняка, что нет.</p>
18
<p>Другими словами, наследование для переопределения поведения хоть и кажется логичным шагом, но в действительности имеет серьёзные ограничения по использованию.</p>
18
<p>Другими словами, наследование для переопределения поведения хоть и кажется логичным шагом, но в действительности имеет серьёзные ограничения по использованию.</p>