匿名函数

实现一个简单的匿名函数:


$func = function() {

    echo "this is a func\n";

};

上面就是一个简单的匿名函数,定义一个函数体,将函数体赋值给一个变量(php5.3之后支持该写法)。

实现闭包

1、当做参数传递:

<?php

// 定义一个匿名函数,赋值给$func

$func = function($param) {

    var_dump($param);

};

// 将匿名函数作为参数传入,并调用该参数

function dFunc($func, $param) {

    $func($param);

}

dFunc($func, '123'); // 输出:string(3) "123"
2、将匿名函数返回:

<?php

// 定义一个函数,在该函数中将内部的匿名函数返回

function cFunc($param) {

    $func = function($param1) use ($param) {

    echo "params:".$param1." ".$param;

};

return $func;

}

// 获取并调用匿名函数

$rCFunc = cFunc("123");

$rCFunc("456"); // params:456 123

捕获外界变量

闭包: 闭包是词法作用于的体现,一个持有外部环境自由变量的函数就是闭包。闭包体现的是在程序运行过程中,由 “不确定”变为“ 确定” 的过程。

捕获外部变量: 在PHP中对捕获这一动作有了更清晰的表现,使用use关键字。如上面例2。

在上面的例2中,匿名函数$func通过use关键字捕获了外部的自由变量$param,在调用时通过传入cFunc()函数的参数123($param此时会变为“确定”状态),进而调用匿名函数时输出“params:456 123”。

use引入的是自由变量的副本。

例如:

<?php

/*

输出结果:

匿名函数执行前:p1:p1

匿名函数内修改后:p1:p2

匿名函数执行完:p1:p1

*/

function f1() {

    $p1 = "p1";

    echo "匿名函数执行前:p1:$p1\n";

    $func = function() use ($p1) {

        $p1 = "p2";

        echo "匿名函数内修改后:p1:$p1\n";

    };

$func();

echo "匿名函数执行完:p1:$p1\n";

}

f1();
golang闭包: 在golang中同样通过匿名函数实现了闭包,和PHP不同的是,golang中的闭包是默认会引入上下文的自由变量,且引入的地址,即在闭包函数内部修改变量会在函数外部生效。

PHP Closure类

用于代表匿名函数类。在PHP中定义一个闭包函数其实就是一个Closure类的实例。

<?php

/*

输出:

object(Closure)#1 (0) {

}

*/

$func = function() {};

    var_dump($func);
类摘要

Closure {

/* 方法 */

__construct ( void )

public static bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] ) : Closure

public bindTo ( object $newthis [, mixed $newscope = 'static' ] ) : Closure

}
  • Closure::__construct — 用于禁止实例化的构造函数
  • Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。
  • Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。

Closure::bind

复制一个闭包,绑定指定的$this对象和类作用域,返回一个新的匿名函数

参数说明:

  • closure: 需要绑定的匿名函数。
  • newthis: 需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包。(理解:可以选择是否将匿名函数绑定到一个类对象,若绑定到了一个类对象,则可以在匿名函数内使用$this,否则不可使用。
  • newscope: 想要绑定给闭包的类作用域,或者 'static' 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性。(理解:如果传入一个类,则可以访问类的static、private、protected属性,否则只能访问public属性。

简单理解:可以简单理解为将该匿名函数绑定到一个类或实例。根据参数的不同,可以访问不同的类的属性。


<?php

class A{

    private static $_cat = 'cat';

    private $_dog = 'dog';

    public $pig = 'pig';

}

$cat = static function() {

    var_dump(A::$_cat);

};

$dog = function() {

    var_dump($this->_dog);

};

$pig = function() {

    var_dump($this->pig);

};

// 传入null,不可使用$this,但传入A类,则可以访问static等

$bindCat = Closure::bind($cat, null, 'A');

echo "bind cat\n";

$bindCat();

// 传入new A()对象,A类,可以使用$this访问私有属性。

$bindDog = Closure::bind($dog, new A(), 'A');

echo "bind dog\n";

$bindDog();

// 为传入类对象,不可使用$this

$bindDog2 = Closure::bind($dog, null, 'A');

echo "bind dog2\n";

$bindDog2();
输出:
bind cat
string(3) "cat"
bind dog
string(3) "dog"
bind dog2
Fatal error: Using $this when not in object context

Closure::bindTo

Closure::bind()的非静态形式。

小结

  • PHP通过匿名函数实现闭包。
  • 可以通过将匿名函数作为参数或返回值实现闭包。
  • 可以通过use关键字引入外部变量,且引入的变量副本。
  • 匿名函数均实现了Closure类,且可以通过Closure::bind()方法将匿名函数绑定到某个类。

hiyanxu
4 声望1 粉丝