Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Динамическая диспетчеризация PHP: Погружаясь в классы

В курсе "PHP: Полиморфизм" мы разбирали как работает полиморфизм изнутри. Но тогда мы ещё не знали про наследование достаточно, чтобы раскрыть этот вопрос полностью. Сейчас пришло время узнать об этом.

Перед тем как начать, нужно вспомнить, что для полиморфизма наследование не нужно. С другой стороны, наследование участвует в процессе выбора метода и об этом тоже нужно знать. Посмотрите на код, который был в курсе, посвящённому полиморфизму:

<?php

// Что происходит во время вызова: $obj->getName() => callMethod($obj, 'getName')
function callMethod($data, $methodName, $args) // функция-диспетчер
{
    $className = $data['className'];
    // Специальная функция, которая хранит список классов и связанных с ними методов
    $methods = getClassMethods($className);
    // Берём нужный метод и вызываем его
    $method = $methods[$methodName];
    if ($method) {
      $method($data, ...$args);
    } else if (!$method && isset($methods['__call'])) {
      // Если метод $method не найден, но определён метод __call, то вызываем его
      $methods['__call']($data, ...$args);
    }

    throw new \Exception('No method error');
}

В этом коде проверка останавливается, если ничего не было найдено. Так было бы без наследования, но с наследованием поиск продолжается. Сначала выбирается базовый класс для текущего и метод ищется там. Если он не найден, то снова проверяется наличие __call(). Затем процесс повторяется для родительского класса родителя текущего класса и далее до конца цепочки наследования.

Из этого, кстати, следует интересный вывод. Метод __call это "тяжелый" вызов. Он требует больше вычислений для поиска. И чем ближе к началу иерархии расположен __call() тем хуже с точки зрения производительности.

Позднее связывание в сравнении с динамической диспетчеризацией

Программисты часто путают позднее связывание и динамическую диспетчеризацию. Ситуация усугубляется тем, что в некоторых языках (например, Java) принято на уровне документации и сообщества подменять одно понятие другим.

Связывание, говорит нам о том, чем является идентификатор, какой у него тип. Если связывание раннее, то мы это знаем сразу, в случае позднего, только в момент вызова кода. Во многих языках можно определить функцию после того, как где-то она используется. Это тоже пример связывания (позднего). В случае $this в PHP, мы знаем что это объект текущей иерархии, но не знаем точно какой класс до момента срабатывания этого кода.

Диспетчеризация же, это процесс поиска и вызова необходимой функции (или метода, в зависимости от языка) для уже известного типа данных.


Дополнительные материалы

  1. What is early and late binding?

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
7 июля 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»