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

Функции высшего порядка PHP: Функции

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

За примерами далеко ходить не придется. Вспомним сортировку. В PHP есть функция sort, которая принимает на вход массив и сортирует его. Казалось бы, все отлично. Но давайте вообразим себе ситуацию, что на вход в программу приходит список пользователей, который нужно отсортировать по возрасту и вывести на экран:

<?php

$users = [
    ['name' => 'Igor', 'age' => 19],
    ['name' => 'Danil', 'age' => 1],
    ['name' => 'Vovan', 'age' => 4],
    ['name' => 'Matvey', 'age' => 16],
];

При таких условиях функция sort становится абсолютно бесполезной, потому что она может сортировать только списки примитивных типов данных. Но выше мы описали всего одну из тысяч возможных ситуаций. Мы можем захотеть сортировать по любому параметру или набору параметров, причем в любом порядке. Сортировки нужны часто, и многие из них довольно сложны. Худшее, что можно начать делать — реализовывать функцию sort под каждую ситуацию.

Так что же делать? В документации PHP можно обнаружить функцию usort. Она сортирует массив по значениям, используя пользовательскую функцию для сравнения элементов:

bool usort ( array &$array , callable $value_compare_func )

Эта функция сортирует элементы массива, используя для сравнения значений колбэк-функцию, предоставленную пользователем. Используйте эту функцию, если вам нужно отсортировать массив по какому-нибудь необычному признаку. Слово callback означает, что мы хотим передать функцию без вызова. Вызывать будет функция usort.

Общая идея состоит в том, что нам не нужно реализовывать алгоритм сортировки каждый раз для каждой ситуации, ведь он не меняется. Все, что меняется — элементы, которые сравниваются между собой в процессе сортировки. Функция usort делегирует взаимодействие с этими элементами вызывающему коду:

<?php

$cmp = function ($a, $b) {
  if ($a['age'] === $b['age']) {
    return 0;
  }
  return $a['age'] > $b['age'] ? 1 : -1;
};

usort($users, $cmp);

print_r($users);
// => [
//      ['name' => 'Danil', 'age' => 1],
//      ['name' => 'Vovan', 'age' => 4],
//      ['name' => 'Matvey', 'age' => 16],
//      ['name' => 'Igor', 'age' => 19],
//    ];

https://replit.com/@hexlet/php-functions-high-order-functions-usort

Функция usort выполняет всю работу по непосредственному перемещению элементов в массиве, но от нас зависит, какой элемент больше или меньше. Достигается подобная схема за счет той самой пользовательской функции, передающейся вторым параметром. Эта функция принимает на вход два параметра — usort отдает в нее два элемента, которые она сравнивает в этот момент. В нашем случае элементы — это пользователи.

Наша задача — внутри этой функции посчитать, что больше или меньше, и сделать следующее:

  • Если элементы равны, нужно вернуть 0
  • Если первый элемент больше второго, нужно считать ошибку в сортировке и вернуть 1
  • Если первый элемент меньше второго, нужно вернуть -1, а usort произведет их сортировку

Из кода выше видно, что внутри функции сравнение переданных пользователей идет по свойству age. Нетрудно догадаться, что эта функция вызывается внутри usort множество раз, то есть на каждое сравнение. Как только она начнет возвращать -1 для каждой пары элементов, сортировка завершена.

Код выше можно упростить, воспользовавшись оператором <=> (spaceship). Он возвращает 1, -1 или 0 в зависимости от соотношения операндов и работает так, как того ожидает сортировка:

<?php

3 <=> 5; // -1 (выражение слева от оператора "<=>" меньше выражения справа)
5 <=> 5; // 0 (выражения слева и справа равны)
5 <=> 3; // 1 (выражение слева больше выражения справа)

Тогда код сокращается до такого:

<?php

$cmp = fn($a, $b) => $a['age'] <=> $b['age'];
usort($users, $cmp);

Функция usort относится к функциям высшего порядка. Такие функции либо принимают другие функции, либо возвращают их, либо делают все сразу. Как правило, они реализуют сортировку или другой обобщенный алгоритм, а ключевую часть логики делегируют нам через колбэк-функцию. Главный плюс от применения таких функций — серьезное повышение коэффициента повторного использования кода.

В примере выше не обязательно создавать переменную для функции. Говоря откровенно, их вообще редко записывают в переменные. Типичное использование выглядит как прямая передача функции в функцию:

<?php

usort($users, fn($a, $b) => $a['age'] <=> $b['age']);

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

Осталось рассмотреть, как происходит вызов внутри. С точки зрения синтаксиса ничего нового не будет:

<?php

function say(callable $fn)
{
    echo $fn();
}

say(fn() => 'hi!'); // => hi!

Функция say делает вызов функции, находящейся внутри переменной $fn. В нашем примере функция возвращает строку, которая тут же выводится на экран.

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


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

  1. PHP The Right Way

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

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

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

Об обучении на Хекслете

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

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

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

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

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

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

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

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

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

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

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

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