PHP高级编程:高阶函数

时间:2022-06-19作者:klpeng分类:PHP浏览:189评论:1

但是什么是高阶函数,我们为什么要使用它呢?它给我们带来了什么好处,我们可以用它来简化我们的代码吗?在本文中,我们将专门讨论 PHP 中的高阶函数,并将展示它们在其他语言中的使用情况以进行比较。

PHP高级编程:高阶函数

什么是高阶函数?

简单来说,变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。你可能看到一个函数的return语句返回一个函数。return 语句可能只是函数的名称,甚至可能是匿名/内联函数。示例如下:

//Simple user-defined function we'll pass to our higher-order 
functionfunction echoHelloWorld(){  
    echo "Hello World!";
}
//Higher-order function that takes a function as an input and calls itfunction 
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()and 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。在这种情况下,我们的计算函数并不关心它所接受的函数是做什么的。它只是将参数传递给函数并返回结果。

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 语法非常相似。


文章原创出自 彭超的博客 | 深入研究web系统架构 https://ligphp.com/

打赏
文章版权声明:除非注明,否则均为彭超的博客原创文章,转载或复制请以超链接形式并注明出处。
相关推荐

  • 评论列表:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

猜你喜欢