##定义(摘抄自PHP手册) 匿名函数(Anonymous functions),也叫闭包函数(closures),允许创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其他应用的情况。

###匿名函数示例一

<?php
    echo preg_replace_callback('~-([a-z])~', function ($match) {
        return strtoupper($match[1]);
    }, 'hello-world');

输出

helloWorld

注意:

上面的正则表达式~-([a-z])~中的~表示正则表达式的边界,相当于平常写的正则表达式的//。因此,上面的正则表达式也可以写作/-([a-z])/

闭包函数也可以作为变量来使用。PHP会把此种表达式转换成内置类Closure的对象实例。把一个closure对象赋值给一个变量的方式与普通变量赋值的语法是一样的。最后也要加上分号作为结束。

###匿名函数变量赋值示例

<?php
    $greet = function($name) {
        printf("Hello %s\r\n", $name);
    };

    $greet('World');
    $greet('PHP');

闭包可以从父作用域中继承变量。任何此类变量都应该使用use语言结构传递进去。

###从父作用域继承变量例子

<?php
    $message = 'hello';

    // 没有使用"use"
    $example = function () {
        var_dump($message);
    };
    echo $example();

    // 继承 $message
    $example = function () use ($message) {
        var_dump($message);
    };
    echo $example();

    // 继承变量的值是当函数定义时继承而不是调用时
    $message = 'world';
    echo $example();

    // 重置$message
    $message = 'hello';

    // 通过引用继承
    $example = function () use (&$message) {
        var_dump($message);
    };
    echo $example();

    // 值在父作用域的改变影响到了函数调用里面的值
    $message = 'world';
    echo $example();

    // 闭包也接收正常的参数
    $example = function ($arg) use ($message) {
        var_dump($arg . ' ' . $message);
    };
    $example("hello");

上面程序的输出是:

Notice: Undefined variable: message in /example.php on line 6
NULL

string(5) "hello"

string(5) "hello"

string(5) "hello"

string(5) "world"

string(11) "hello world"

这些变量必须在函数或者类的头部声明。从父作用域中继承变量与使用全局变量是不同的。全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而闭包的父作用域是定义该闭包的函数(不一定是调用它的函数)。

##递归 如果需要递归地调用闭包的话,使用下面的代码:

<?php
    $recursive = function () use (&$recursive) {
        //$recursive函数是有效的
    };

    //这样并不行
    $recusive = function() use ($recursive) {
        //$recursive并不能被识别
    };

##注意

1.当’引入’变量到闭包的作用域时,很容易忽略/忘记它们是真的被拷贝到闭包的作用域里而不是仅仅作为可以的值。

因此当你需要在闭包里改变变量的时候,你应该使用引入变量的方式传入。

2.当你调用一个保存在实例化的变量的闭包时是无效的,如下面的代码所示:

<?php
    $obj = new StdClass();

    $obj->func = function() {
        echo "hello";
    }
    
    //$obj->func(); 并不能执行

    //应该这样调用:
    $func = $obj->func();
    $func();

    //或者
    call_user_func($obj->func);

    //但是,这样的方式也是可以的:
    $array['func'] = function() {
        echo 'hello';
    };

    $array['func']();

##跟Javascript的闭包的几点比较 上面提到,在PHP中通过值传递是这样的

<?php
    $message = 'hello';
    $example = function () use ($message) {
        var_dump($message);
    };
    $message = 'world';
    $example();

上面输出的是hello

在Javascript的闭包可以通过下面的例子实现相同的效果

var message = 'hello';

var func = (function(message) { return function{ alert(message);}})(message);
message = 'world';
func();//输出hello

PHP中在使用闭包时的引用传递如下:

<?php
    $message = 'hello';
    $example = function () use (&$message) {
        var_dump($message);
    };
    $message = 'world';
    $example();

上面输出的是world

在Javascript中可以这么实现达到相同的效果:

var message = 'hello';
var func = function() { alert(message); };
message = 'world';
func();//输出world

PHP的闭包与Javascript的闭包有很大的不同。刚开始看到上面的差别时并没有弄懂,后来通过请教同学之后才知道了为什么。上面两端Javascript的不同是因为在Javascript中并没有块作用域以及两个语言之间本身的解析机制的不同。具体的解释日后再写一篇作解释。

分享到: 微信 更多