Создание сайтов в Миусинске, ЛНР. Функциональное программирование на PHP: функции высшего порядка

Если вы изучите несколько фреймворков и крупномасштабных приложений, вы наверняка увидите в какой-то момент функцию более высокого порядка. Многие языки поддерживают идею функций высшего порядка, включая JavaScript, Java,.NET, Python и даже PHP, и это лишь некоторые из них.

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

Первоклассные функции

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

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

Что такое функции высшего порядка?

Есть две основные характеристики, которые идентифицируют функцию более высокого порядка. Функция высшего порядка может реализовать только одну или обе из следующих идей: функция, которая принимает одну или несколько функций в качестве входных данных или возвращает функцию в качестве выходных данных. В PHP есть ключевое слово, которое явно указывает на то, что функция имеет более высокий порядок: ключевое слово callable. Хотя это ключевое слово не обязательно должно присутствовать, ключевое слово упрощает их идентификацию. Если вы видите функцию или метод, который имеет вызываемый параметр, это означает, что он принимает функцию в качестве входных данных. Еще один простой признак — если вы видите, что функция возвращает функцию, используя свой returnоператор. Оператор return может быть просто именем функции или может быть даже анонимной/встроенной функцией. Ниже приведены несколько примеров каждого типа.

// Simple user-defined function we’ll pass to our higher-order function

function echoHelloWorld () {

echo «Hello World!»;

}

// Higher-order function that takes a function as an input and calls it

function higherOrderFunction (callable $func) {

$func () ;

}

// Call our higher-order function and give it our echoHelloWorld () function.

// Notice we pass just the name as a string and no parenthesis.

// This echos «Hello World!»

higherOrderFunction ('echoHelloWorld’) ;

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

// Returns an existing function in PHP called trim (). Notice it’s a simple string with no parentheses.

function trimMessage1 () {

return 'trim’;

}

// Here’s an example using an anonymous inline function

function trimMessage2 () {

return function ($text) {

return trim ($text) ;

};

}

// Returns the 'trim’ function

$trim1 = trimMessage1 () ;

// Call it with our string to trim

echo $trim1 (' hello world ') ;

// Returns the anonymous function that internally calls 'trim’

$trim2 = trimMessage1 () ;

// Call it again with our string to trim

echo $trim2 (' hello world ') ;

Как вы понимаете, вы можете взять функцию и использовать ее для генерации другой возвращаемой функции. Довольно изящный трюк, не так ли? Но зачем вам все это? Звучит как нечто, что просто усложнит ситуацию.

Зачем вам использовать или создавать функцию высшего порядка?

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

Добавление гибкости кода

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

Возможно, сама функция высшего порядка не знает, какой тип функции она получит. Кто сказал, что функция должна что-то знать о функции, которую она принимает? В одну минуту входная функция может быть add () функцией, а в следующую — divide () функцией. В любом случае это просто работает.

Легко расширяйте свой код

Эта функциональность также упрощает добавление дополнительных функций ввода позже. Допустим, у вас есть add () и divide (), но в будущем вам нужно добавить sum () функцию. Вы можете написать sum () функцию и передать ее через функцию более высокого порядка, даже не изменяя ее. В следующем примере мы покажем, как мы можем использовать эту функциональность для создания нашей собственной calc () функции.

Имитировать черты другого языка

Другая причина, по которой вы можете захотеть использовать функцию более высокого порядка в PHP, — это имитация поведения чего-то вроде декоратора в Python. Вы «обертываете» функцию внутри другой функции, чтобы изменить поведение этой функции. Например, вы можете написать функцию, которая измеряет время других функций. Вы пишете функцию более высокого порядка, которая принимает функцию, запускает таймер, вызывает функцию, а затем останавливает таймер, чтобы увидеть, сколько времени прошло.

Примеры существующих функций высшего порядка в PHP

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

Динамический дуэт высшего порядка: array_mapиarray_filter

$arrayOfNums = [1,2,3,4,5];

// array_map: example of taking an inline anonymous function

$doubledNums = array_map (function ($num) {

return $num * 2;

}, $arrayOfNums) ;

var_dump ($doubledNums) ; // Prints out array containing [2, 4, 6, 8, 10];

Давайте посмотрим, как использовать еще один, на этот раз с функцией фильтра, которую мы определили отдельно:

$arrayOfNums = [1,2,3,4,5];

// Example of creating a function and giving it to a higher-order function array_filter ()

function isEven ($num) {

return ($num% 2) === 0;

}

// array_filter is a higher-order function

$evenNums = array_filter ($arrayOfNums, 'isEven’) ;

var_dump ($evenNums) ; // Prints out array containing [2, 4]

array_filterи array_mapдве очень популярные функции высшего порядка, которые вы найдете во многих проектах кода. Другой, который вы можете использовать, это call_user_func, который принимает функцию и список аргументов и вызывает эту функцию. По сути, это настраиваемая функция высшего порядка. Вся его цель состоит в том, чтобы вызывать другие функции, определенные пользователем:

function printCustomMessage ($message) {

echo «$message»;

}

call_user_func ('printCustomMessage’, 'Called custom message through the use of call_user_func!') ;

Как создать свои собственные функции высшего порядка

Мы показали множество примеров того, как функции высшего порядка работают в PHP, и уже создали несколько пользовательских, чтобы продемонстрировать их различные цели. Но давайте еще немного продемонстрируем гибкость с помощью новой функции, которую мы назовем calc (). Эта функция будет принимать два аргумента и функцию, которая будет работать с этими двумя аргументами, чтобы дать нам результат:

function add ($a, $b) {

return $a + $b;

}

function subtract ($a, $b) {

return $a — $b;

}

function multiply ($a, $b) {

return $a * $b;

}

// Higher-order function that passes along $n1 and $n2

function calc ($n1, $n2, $math_func) {

return $math_func ($n1, $n2) ;

}

$addedNums = calc (1, 5, 'add’) ;

$subtractedNums = calc (1, 5, 'subtract’) ;

$multipliedNums = calc (1, 5, 'multiply’) ;

// Prints 6

echo «Added numbers: $addedNums\n»;

// Prints -4

echo «Subtracted numbers: $subtractedNums\n»;

// Prints 5

echo «Multiplied numbers: $multipliedNums\n»;

Обратите внимание, что наша calc () функция была написана очень обобщенно, чтобы принимать набор других функций и вызывать их с параметрами $n1и $n2. В этом случае нашей вычислительной функции все равно, что делает функция, которую она принимает. Он просто передает параметры функции и возвращает результат.

Но подождите минутку: наш начальник только что попросил нас добавить функцию для сложения двух строк в нашу существующую систему. Но объединение строк — это не обычная математическая операция. Однако с нашей настройкой здесь нам просто нужно добавить конкатенацию строк и передать ее через calc ():

function addTwoStrings ($a, $b) {

return $a. ««. $b;

}

// Prints «Hello World!»

$concatenatedStrings = calc ('Hello’, 'World!', 'addTwoStrings’) ;

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

Как это соотносится с другими языками, имеющими функции более высокого порядка? Давайте возьмем простой пример декоратора на Python и сравним его с JavaScript, а затем сравним его с PHP. Таким образом, если вы знаете Python или JS, вы можете увидеть, как они эквивалентны.

Параллельное сравнение с Python и JavaScript

def say_message (func):

def wrapper ():

print ('Print before function is called’)

func ()

print ('Print after function is called’)

return wrapper

def say_hello_world ():

print («Hello World!»)

# Pass our hello world function to the say_message function.

# It returns a function that we can then call

# Note: This line could have been replaced with the @say_message (pie syntax) on the say_hello_world method

say_hello_world = say_message (say_hello_world)

# Call the created function

say_hello_world ()

# Output...

# Print before function is called

# Hello World!

# Print after function is called

Теперь давайте посмотрим, как этого можно добиться в функциях высшего порядка JavaScript:

// Takes a function, returns a function.

function say_message (func) {

return function () {

console.log («Print before function is called») ;

func () ;

console.log («Print after function is called») ;

}

}

function say_hello_world () {

console.log («Hello World!») ;

}

// Again pass our function to say_message as an input parameter

// say_message returns a function that is wrapped around the say_hello_world function

say_hello = say_message (say_hello_world) ;

// Call the function

say_hello () ;

// Output...

// Print before function is called

// Hello World!

// Print after function is called

Теперь, наконец, давайте сравним это с PHP:

// Takes a function, returns a function.

function say_message ($func) {

// We use 'use’ so that our anonymous function can see $func coming in

return function () use ($func) {

echo «Print before function is called»;

$func () ;

echo «Print after function is called»;

};

}

function say_hello_world () {

echo «Hello World!»;

}

// Again pass our function to say_message as an input parameter

// say_message returns a function that is wrapped around the say_hello_world function

$say_hello = say_message ('say_hello_world’) ;

// Call the function

$say_hello () ;

// Output...

// Print before function is called

// Hello World!

// Print after function is called

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

Краткое слово о лямбда-выражениях/анонимных функциях

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

Заключение

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

Затем мы показали несколько примеров существующих в PHP функций высшего порядка, таких как array_mapи array_filter, а затем перешли к созданию собственной функции высшего порядка с именем calc (), которая принимала несколько входных функций и работала с парой аргументов. Затем мы провели параллельное сравнение, показав, как выглядит решение PHP по сравнению с декоратором Python и реализацией JavaScript.

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

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

Делитесь нашими материалами с друзьями!

 

 

Заказать разработку сайта