PHP

PHP闭包函数特性详细解析

silverwq
2022-06-01 / 0 评论 / 255 阅读 / 正在检测是否收录...

一、概述

在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) {
};

如上定义的闭包对象,会如下所示:
VeryCapture_20220524173600.jpg

由于多次调用匿名函数,都是操作同一个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();
0

评论 (0)

取消