Зарегистрируйтесь для доступа к 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-функцию, предоставленную пользователем. Используйте эту функцию, если вам нужно отсортировать массив по какому-нибудь необычному признаку. Слово 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 относится к так называемым функциям высшего порядка (high order functions). Функции высшего порядка — это функции, которые либо принимают, либо возвращают другие функции, либо делают все сразу. Такие функции, как правило, реализуют некий обобщённый алгоритм (например, сортировку), а ключевую часть логики делегируют вам через callback-функцию. Главный плюс от применения таких функций — серьёзное повышение коэффициента повторного использования кода.

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

<?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 месяцев
с нуля
Старт 1 июня

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

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

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

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