一、概述
在php里,没有名称的函数叫做匿名函数,如下所示:
function() {
echo 123;
};
匿名函数本质上是闭包类Closure的对象,所以跟普通对象一样:可以赋值给变量,可以作为函数的参数。
// 声明一个匿名函数,并赋值给变量
$stringToUpper = function ($match) {
return strtoupper($match[1]);
};
// 匿名函数作为回调函数的参数
echo preg_replace_callback('~-([a-z])~', $stringToUpper , 'hello-world');
// 匿名函数属于闭包类Closure
var_dump($stringToUpper instanceof Closure);// true
二、变量语法
跟普通函数一样,在匿名函数里是无法直接使用函数外部的变量的,如下所示
$message = 'hello';
$example = function () {
print_r($message);
};
// 输出null
$example();
跟普通函数一样,我们还可以定义参数:
// 定义普通的参数$arg
$example = function ($arg) {
var_dump($arg);
};
// 调用的是传入普通的参数hello
$example("hello");
匿名函数还有一个很重要的特性,use语法。我们定义匿名函数的时候,相当于实例化Closure类对象,use定义的参数则像往对象身上添加属性,并且赋予初始值。所有匿名函数定义的参数,和use里使用的变量,都会在closure上体现出来:
$tmp = "";
$closure = function ($parma) use ($tmp) {
};
如上定义的闭包对象,会如下所示:
由于多次调用匿名函数,都是操作同一个Clourse对象实例,所以属性值也是同一个对象上的属性,不会被清空:
$closure = function () {
$tmp = 1;// 临时变量,作用域在这个匿名函数内,用于初始化
// 引用的方式继承
return function () use ($tmp) {
print_r($tmp."\r\n");// 调用Closure对象的->tpm属性
$tmp++;// 相当于在Closure对象的->tpm属性上相加
};
};
$closureObject = $closure();
$closureObject();// 输出是1
$closureObject();//输出是2
有时候,我们希望能够在闭包里改变外部变量的值,这个时候可以通过引用的方式传递变量即可。
$message = 'hello';
// 引用的方式继承
$example = function () use (&$message) {
print_r($message);
};
$example();// 输出hello
// 父作用域的值改变了,匿名函数里的值也会被改变
$message = 'world';
$example();
三、$this
的作用域
我们已经知道,匿名函数是一个Closure类的对象,所以也会有$this
特殊变量,那么这个变量到底是指向谁呢?如果匿名函数在类的上下文中,匿名函数里的 $this
自动绑定到当前类,例如下面的示例中的testing方法里的$this
是Test类对象,所以可以访问到Test类的name属性。
class Test
{
protected $name = 'test';
public function testing()
{
return function() {
print_r($this->name);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
如果匿名函数不在类中,这样使用是没有意义的:
$testThis = function () {
var_dump($this);// 输出null
};
$testThis();
有时候,我们不喜欢匿名函数里访问到类的$this
变量,这个时候可以使用静态匿名函数,只需要在匿名函数前面加个一个static声明即可,此时匿名函数里的$this
将会是null:
class Test
{
public function testing()
{
$func = static function() {
print_r($this);// $this将变成null
};
$func();
}
}
$object = new Test;
$object->testing();
静态匿名函数,还能限制将对象绑定到闭包的$this
:
$func = static function() {
var_dump($this);// null
};
$func = $func->bindTo(new StdClass);// 将对象绑定到匿名函数将不允许
$func();