HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>Устранение дублирования кода - не единственная задача наследования классов. Иногда оно применяется для изменения существующего поведения базового класса.</p>
1 <p>Устранение дублирования кода - не единственная задача наследования классов. Иногда оно применяется для изменения существующего поведения базового класса.</p>
2 <p>Тег &lt;select&gt; в DOM представлен классом<em>HTMLSelectElement</em>. У него есть дополнительные методы, которые нужны для работы со списком элементов. Один из таких методов: item(index). С его помощью можно извлекать конкретный вариант из списка.</p>
2 <p>Тег &lt;select&gt; в 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>