Зарегистрируйтесь, чтобы продолжить обучение

Параметрический полиморфизм PHP: Полиморфизм

Слово "полиморфизм" в зависимости от контекста может означать разные вещи. Когда о полиморфизме говорят программисты на императивных языках, они, как правило, подразумевают "полиморфизм подтипов". В то же время программисты на функциональных языках имеют в виду "параметрический полиморфизм". О последнем и поговорим.

В этом уроке появляется код на Java. Не переживайте, если не понимаете его до конца, наша цель — разобраться с концепциями, а не с Java.

В PHP есть встроенная функция array_merge(), которая объединяет переданные ей массивы:


<?php

array_merge([1], [2, 3, 1]); // [1, 2, 3, 1]
array_merge(['one'], ['two', 'three']); // ['one', 'two', 'three']
array_merge([true], [false, false, true]); // [true, false, false, true]

Эта функция объединяет любые массивы, независимо от типа данных, содержащихся внутри. Попробуем реализовать её самостоятельно.

<?php

// Это немного урезанная версия функции array_merge, она работает только с двумя аргументами
// Функция создает новый массив, затем обходит по очереди переданные массивы и добавляет их значения
// во вновь созданный массив. Затем он возвращается наружу.
function myArrayMerge(array $first, array $last)
{
    $result = [];
    foreach ($first as $value) {
        $result[] = $value;
    }
    foreach ($last as $value) {
        $result[] = $value;
    }
    return $result;
}

Посмотрите внимательно на этот код. Выполняются ли в нём какие-либо операции над данными внутри массива? Ответ: нет. Эти данные перекладываются из одного массива в другой, но над ними не происходит никаких действий. Наша новая функция myArrayMerge(), также как и исходная array_merge() может работать с массивами, содержащими любые типы данных.

Для разработчиков, которые писали только на динамических языках, такое поведение кажется естественным, но в статических языках не всё так просто. Ниже пример определения массивов в Java:

int numbers[] = {3, 1, 2, 5, 4};
String words[] = {"one", "two", "three"};

В глаза бросается необходимость указывать тип. Для первого массива это int, для второго String. Нельзя создать массив без указания типа его значений. То же самое касается функций, обрабатывающих массивы:

class Main {
    public static void main(String[] args) {
      int[] a = {1, 2, 3, 4};
      int[] b = {4, 16, 1, 2, 3, 22};
      myArrayMerge(a, b);
    }

    public static int[] myArrayMerge(int[] first, int[] last) {
        int[] result = new int[first.length + last.length];
        int count = 0;

        for (int i = 0; i < first.length; i++) {
           result[i] = first[i];
           count++;
        }

        for (int j = 0; j < last.length; j++) {
           result[count] = last[j];
           count++;
        }

        return result;
    }
}

Обратите внимание на сигнатуру метода myArrayMerge(): int[] myArrayMerge(int[] first, int[] last). В отличие от варианта на PHP, здесь указано, что входными параметрами являются массивы чисел. То есть для массива строк эта функция работать не будет. Не будет она работать и для всех остальных типов данных.

Что это означает на практике? Очень простую и печальную вещь. Нам придётся реализовывать подобную функцию для каждого типа, при том что алгоритм внутри абсолютно идентичен.

Именно тут нам пригодится параметрический полиморфизм. Статическим языкам приходится вводить в язык специальные конструкции, которые позволяют описывать подобные алгоритмы безотносительно типа параметра. В некоторых языках их называют шаблонами (C++) или дженериками (Java, C#):

class Main {
  public static void main(String[] args) {
    Integer[] a = {1, 2, 3, 4};
    Integer[] b = {4, 16, 1, 2, 3, 22};
    myArrayMerge(a, b);
  }

  public static<T> T[] myArrayMerge(T[] first, T[] last) {
      T[] result = (T[]) new Object[first.length + last.length];
      int count = 0;

      for (int i = 0; i < first.length; i++) {
         result[i] = first[i];
         count++;
      }

      for (int j = 0; j < last.length;j++) {
         result[count] = last[j];
         count++;
      }

      return result;
  }
}

В этом коде появляется тип T, что как раз и означает возможность использования с любым типом внутри массива. Теперь функция myArrayMerge работает подобно аналогу из PHP.

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

В динамических языках для реализации обобщённых алгоритмов, параметрический полиморфизм не нужен. Любая коллекция может содержать любые типы данных в любой момент времени. Благодаря этому не требуется вводить дополнительных языковых конструкций и изучать новые концепции.

В литературе использование параметрического полиморфизма часто называется обобщённым программированием.


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

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

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

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

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

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

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

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

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

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

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Laravel
10 месяцев
с нуля
Старт 26 декабря

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

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

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

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»