浅谈PHP匿名函数和闭包

概述

闭包和匿名函数在PHP 5.3.0中引入,这两个特性非常有用,每个PHP开发者都应该掌握。

匿名函数其实就是没有名称的函数,匿名函数可以赋值给变量,还能像其他任何PHP函数对象那样传递。不过匿名函数仍然是函数,因此可以调用,还可以传入参数,适合作为函数或方法的回调。

闭包是指在创建时封装周围状态的函数,即使闭包所在的环境的不存在了,闭包中封装的状态依然存在。

创建匿名函数

创建匿名函数很简单:

//将匿名函数赋给一个变量,通过变量名+()的形式来调用
$greet = function () {
 return "Hello World";
};

echo $greet();

结果打印:

Hello World

匿名函数和普通的PHP函数很像:常用的句法相同,也接受参数,而且能返回值。不过闭包没有函数名。

注:我们之所以能调用$greet变量,是因为这个变量的值是一个闭包,而且闭包对象实现了__invoke()魔术方法,只要变量名后有(),PHP就会查找并调用__invoke方法。

我们通常把匿名函数当做函数或方法的回调使用,事实上,很多PHP函数都会用到匿名函数,比如array_mappreg_replace_callback,这是使用PHP匿名函数的绝佳时机。记住,闭包和其他值一样,可以作为参数传入其他PHP函数:

$numberPlusOne = array_map(function ($number) {
 return $number += 1;
}, [1, 2, 3]);

print_r($numberPlusOne);

在匿名函数出现之前,要实现这样的功能,PHP开发者只能单独创建具名函数,然后使用名称引用这个函数:

function incrementNumber ($number) {
 return $number += 1;
}

$numberPlusOne = array_map(‘incrementNumber', [1, 2, 3]);
print_r($numberPlusOne);

这样做把回调的实现和使用场所隔离开了,而且使用闭包实现代码更加简洁。

创建闭包

包含自由变量的函数与为所有这些自由变量提供了变量绑定的环境一起,被称为闭包。

function makeHelloWorld($name) {
 $i = 0;
 return function()use($name, &$i){
  echo $name.$i. ' <br>';
  $i++;
 };

}
$hello1 = makeHelloWorld("itbsl");
$hello2 = makeHelloWorld("kevin");
$hello1();
$hello1();
$hello1();
$hello2();

打印结果:

itbsl0
itbsl1
itbsl2
kevin0

从父作用域继承变量

在PHP中必须手动调用闭包对象的bindTo方法或使用use关键字把父作用域的变量及状态附加到PHP闭包中。而实际应用中,又以使用use关键字实现居多。

use关键字

实际上,Laravel框架中也大量使用了闭包,最常见的比如路由定义:

Route::group(['domain' => '{account}.myapp.com'], function () {
 Route::get('user/{id}', function ($account, $id) {
  //
 });
});

这里面的两个function都是匿名函数。而从父作用域继承变量的使用场景在Laravel底层源码中也是俯拾即是,比如Model.php(Illuminate\Database\Eloquent)的saveOrFail方法:

该方法的作用是使用事务将模型数据保存到数据库,这里面我们使用匿名函数返回保存状态,同时使用use关键字将父作用域的$options传递给该闭包以便其能够访问这个数据。

此外,还支持传递多个父作用域变量到匿名函数,比如还是在Model类中的forceFill方法:

多个变量以逗号分隔即可。

bindTo方法

我们在前面已经提到,闭包是一个对象,所以我们可以在闭包中使用$this关键字获取闭包的内部状态,闭包对象的默认状态没什么用,需要注意的是其中的__invoke魔术方法和bindTo方法。

__invoke的作用前面已经说过,当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。

接下来我们来看看bindTo方法,通过该方法,我们可以把闭包的内部状态绑定到其他对象上。这里bindTo方法的第二个参数显得尤为重要,其作用是指定绑定闭包的那个对象所属的PHP类,这样,闭包就可以在其他地方访问邦定闭包的对象中受保护和私有的成员变量。

你会发现,PHP框架经常使用bindTo方法把路由URL映射到匿名回调函数上,框架会把匿名回调函数绑定到应用对象上,这样在匿名函数中就可以使用$this关键字引用重要的应用对象:

class App {
 protected $routes = [];
 protected $responseStatus = '200 OK';
 protected $responseContentType = 'text/html';
 protected $responseBody = 'Laravel学院';

 public function addRoute($routePath, $routeCallback) {
  $this->routes[$routePath] = $routeCallback->bindTo($this, __CLASS__);
 }

 public function dispatch($currentPath) {
  foreach ($this->routes as $routePath => $callback) {
   if( $routePath === $currentPath) {
    $callback();
   }
  }
  header('HTTP/1.1 ' . $this->responseStatus);
  header('Content-Type: ' . $this->responseContentType);
  header('Content-Length: ' . mb_strlen($this->responseBody));
  echo $this->responseBody;
 }

}

这里我们需要重点关注addRoute方法,这个方法的参数分别是一个路由路径和一个路由回调,dispatch方法的参数是当前HTTP请求的路径,它会调用匹配的路由回调。第9行是重点所在,我们将路由回调绑定到了当前的App实例上。这么做能够在回调函数中处理App实例的状态:

$app = new App();
$app->addRoute(‘user/nonfu', function(){
 $this->responseContentType = ‘application/json;charset=utf8';
 $this->responseBody = ‘{“name”:”LaravelAcademy"}';
});
$app->dispatch(‘user/nonfu');
在Larval底层也有用到bindTo方法,详见Illuminate\Support\Traits\Macroable的__call方法:

以上所述是小编给大家介绍的PHP匿名函数和闭包详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 浅析PHP中的闭包和匿名函数

    闭包是指在创建时封装周围状态的函数.即使闭包所在的环境不存在了,闭包中封装的状态依然存在. 匿名函数就是没有名称的函数.匿名函数可以赋值给变量,还能像其他任何PHP对象那样传递.不过匿名函数仍是函数,因此可以调用,还可以传入参数.匿名函数特别适合作为函数或方法的回调. 注意:理论上讲,闭包和匿名函数是不同的概念.不过,PHP将其视作相同的概念.所以,我们提到闭包时,指的也是匿名函数,反之亦然. PHP闭包和匿名函数使用的句法与普通函数相同,但闭包和匿名函数其实是 伪装成函数的对象(Closure

  • php的闭包(Closure)匿名函数详解

    php的闭包(Closure)也就是匿名函数,是PHP5.3引入的. 闭包的语法很简单,需要注意的关键字就只有use,use是连接闭包和外界变量. 复制代码 代码如下: $a = function() use($b) {} 简单例子如下: 复制代码 代码如下: function callback($fun) { $fun(); } $msg = "Hello, everyone"; $fun = function () use($msg) { print "This is a

  • PHP中的闭包(匿名函数)浅析

    闭包也叫匿名函数 PHP5.3 引入. 使用方法 需要调整数组元素中的值 复制代码 代码如下: $data = range(0, 100);//想要每个元素的值都加上.html的后缀 $suffix = '.html'; function makeSuffix($str, $suffix) {     return $str . $suffix; } $new_data = array_map(function($item) use ($suffix) {     return makeSuff

  • php的闭包(Closure)匿名函数初探

    提到闭包就不得不想起匿名函数,也叫闭包函数(closures),貌似PHP闭包实现主要就是靠它.声明一个匿名函数是这样: $func = function() { }; //带结束符 可以看到,匿名函数因为没有名字,如果要使用它,需要将其返回给一个变量.匿名函数也像普通函数一样可以声明参数,调用方法也相同: $func = function( $param ) { echo $param; }; $func( 'some string' ); //输出: //some string 顺便提一下,

  • 浅谈PHP匿名函数和闭包

    概述 闭包和匿名函数在PHP 5.3.0中引入,这两个特性非常有用,每个PHP开发者都应该掌握. 匿名函数其实就是没有名称的函数,匿名函数可以赋值给变量,还能像其他任何PHP函数对象那样传递.不过匿名函数仍然是函数,因此可以调用,还可以传入参数,适合作为函数或方法的回调. 闭包是指在创建时封装周围状态的函数,即使闭包所在的环境的不存在了,闭包中封装的状态依然存在. 创建匿名函数 创建匿名函数很简单: //将匿名函数赋给一个变量,通过变量名+()的形式来调用 $greet = function (

  • 浅谈JS封闭函数、闭包、内置对象

    一.变量作用域指的是变量的作用范围,javascript中的变量分为全局变量和局部变量 1.全局变量:在函数之外定义的变量,为整个页面公用,函数的内部外部都可以访问. 2.局部变量:在函数内部定义的变量,只能在定义该变量的函数内部访问,外部无法访问.函数内部访问变量时,先在内部查找是否有此变量,如果有,就使用内部,如果没有,就去外部查找 二.封闭函数封闭函数是javascript中匿名函数的另外一种写法,创建一个一开始就执行而不用命名的函数. 1.一般函数的定义和执行函数 2.封闭函数的定义和执

  • 浅谈Javascript嵌套函数及闭包

    [嵌套函数] JavaScript允许嵌入的函数,允许函数用作数据,并且在函数词法作用域下面,可以产生与传统面向对象语言不同的惊人地方. 首先,JavaScript的函数是通过词法来划分作用域的,而不是动态的划分作用域的,于是,函数的是在定义它们的作用域中运行,而不是在执行它们的作用域中运行,所以,当嵌套函数和它的外围函数定义在同一个词法作用域中的时候,是很容易理解的.比如下面很平淡无奇的代码: 复制代码 代码如下: var x = 'global'; function f () { var x

  • 浅谈JavaScript function函数种类

    本篇主要介绍普通函数.匿名函数.闭包函数 1.普通函数介绍 1.1 示例 复制代码 代码如下: function ShowName(name) {     alert(name); } 1.2 Js中同名函数的覆盖 在Js中函数是没有重载,定义相同函数名.不同参数签名的函数,后面的函数会覆盖前面的函数.调用时,只会调用后面的函数. 复制代码 代码如下: var n1 = 1;   function add(value1) {     return n1 + 1; } alert(add(n1))

  • 浅谈Python中函数的参数传递

    1.普通的参数传递 >>> def add(a,b): return a+b >>> print add(1,2) 3 >>> print add('abc','123') abc123 2.参数个数可选,参数有默认值的传递 >>> def myjoin(string,sep='_'): return sep.join(string) >>> myjoin('Test') 'T_e_s_t' >>>

  • JavaScript 匿名函数和闭包介绍

    匿名函数:没有名字的函数; 闭包:可访问一个函数作用域里的变量的函数; 一 匿名函数 // 普通函数 function box(){ // 函数名是box; return 'Lee'; } box(); // =>Lee; 调用函数; // 匿名函数 function(){ // 匿名函数,会报错; return 'Lee'; } // 通过表达式自我执行 (function(name){ console.log(name); // =>Lee; })("Lee"); //

  • 浅谈PHP eval()函数定义和用法

    eval() 函数把字符串按照 PHP 代码来计算. 该字符串必须是合法的 PHP 代码,且必须以分号结尾. 如果没有在代码字符串中调用 return 语句,则返回 NULL.如果代码中存在解析错误,则 eval() 函数返回 false. 语法 eval(phpcode) 参数 描述 phpcode 必需.规定要计算的 PHP 代码.  提示和注释 注释:返回语句会立即终止对字符串的计算. 注释:该函数对于在数据库文本字段中供日后计算而进行的代码存储很有用. 例子 <?php $string

  • 浅谈python socket函数中,send与sendall的区别与使用方法

    在python socket编程中,有两个发送TCP的函数,send()与sendall(),区别如下: socket.send(string[, flags]) 发送TCP数据,返回发送的字节大小.这个字节长度可能少于实际要发送的数据的长度.换句话说,这个函数执行一次,并不一定能发送完给定的数据,可能需要重复多次才能发送完成. 例子: data = "something you want to send" while True: len = s.send(data[len:]) if

  • 浅谈使用splice函数对数组中的元素进行删除时的注意事项

    使用splice函数对数组中的元素进行删除时的注意事项 删除值为c的元素: <script> var arr = new Array(); arr[0] = 'a'; arr[1] = 'b'; arr[2] = 'c'; arr[3] = 'c'; arr[4] = 'e'; for(var i=0; i<arr.length; i++){ if(arr[i] == 'c'){ arr.splice(i,1); i=i-1; // 必须对i减去1,否则后面的一个元素会被跳过去 } }

  • javascript笔记之匿名函数和闭包

    本文介绍了js匿名函数和闭包的相关内容,供大家参考,具体内容如下 匿名函数 <script type="text/javascript"> //function(){}//会报错 var fun = function(){};//将匿名函数赋值给变量 (function(){})();//匿名函数自执行 function(){ return function(){};//函数里的匿名函数 } </script> 闭包 闭包是指有权访问另一个函数作用域中的变量的函

随机推荐