美文网首页
PHP 闭包那些事儿

PHP 闭包那些事儿

作者: 枫恋寒 | 来源:发表于2018-03-16 00:02 被阅读0次

匿名函数

匿名函数,也叫闭包函数,说白了就是“没有名字的函数”,和一般函数结构一样,只是少了函数名以及最后需要加上分号;

注:理论上讲闭包和匿名函数是不同的概念,不过PHP将其视作相同的概念。

$func = function()
{
    echo 'Hello World' . PHP_EOL;
};
$func();

匿名函数和普通函数的区分有:

  • 匿名函数也可以作为变量的值来使用。
  • 匿名函数可以从父作用域继承变量,而这个父作用域是定义该闭包的函数(不一定是调用它的函数)。
$message = 'hello';
$example = function () use ($message) {
    return $message;
};
$message = 'world';
echo $example();

输出:hello

注意:必须使用use关键字将变量传递进去才行,具体见官方文档

闭包类

定义一个闭包函数,其实就是实例化一个闭包类(Closure)对象:

$func = function()
{
    echo 'hello world' . PHP_EOL;
};
var_dump($func);

输出:
object(Closure)#1 (0) {
}

类摘要:

Closure {
     __construct ( void )
     public static Closure bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] )
     public Closure bindTo ( object $newthis [, mixed $newscope = 'static' ] )
}

除了以上方法,闭包还实现了一个__invoke()魔术方法,当尝试以调用函数的方式调用一个对象时,__invoke()方法会被自动调用。

bindTo 方法

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

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

class App {
    protected $routes = [];
    protected $responseStatus = '200 OK';
    protected $responseContentType = 'text/html';
    protected $responseBody = 'Hello World';

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

    public function dispatch($path) {
        foreach ($this->routes as $routePath => $callback) {
            if( $routePath === $path) {
                $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’, function(){
    $this->responseContentType = ‘application/json;charset=utf8’;
    $this->responseBody = '世界你好';
});
$app->dispatch('/user');

IoC 容器

匿名函数可以从父作用域继承变量,而这个父作用域是定义该闭包的函数(不一定是调用它的函数)。

利用这个特性,我们可以实现一个简单的控制反转IoC容器:

class Container
{
    protected static $bindings;
 
    public static function bind($abstract, Closure $concrete)
    {
        static::$bindings[$abstract] = $concrete;
    }
 
    public static function make($abstract)
    {
        return call_user_func(static::$bindings[$abstract]);
    }
}
 
class talk
{
    public function greet($target)
    {
        echo 'Hello ' . $target->getName();
    }
}

class A
{
    public function getName()
    {
        return 'World';
    }
}
 
// 创建一个talk类的实例
$talk = new talk();
 
// 将A类绑定至容器,命名为foo
Container::bind('foo', function() {
    return new A;
});
 
// 通过容器取出实例
$talk->greet(Container::make('foo')); // Hello World

上述例子中,只有在通过make方法获取实例的时候,实例才被创建,这样使得我们可以实现容器。

Laravel框架底层也大量使用了闭包以及bindTo方法,利用好闭包可以实现更多的高级特性如事件触发等。

相关文章

  • PHP 闭包那些事儿

    匿名函数 匿名函数,也叫闭包函数,说白了就是“没有名字的函数”,和一般函数结构一样,只是少了函数名以及最后需要加上...

  • php之闭包函数(Closure)

    php闭包函数(Closure) JS闭包 js和php闭包使用和区别

  • 关于闭包那些事儿

    本文作者:vicky 原文出处:http://www.mamicode.com/info-detail-5006...

  • 2019-03-25 js闭包和内存释放

    闭包的那些事儿 怎么写一个闭包闭包是什么就不解释了,直接写一个闭包函数: js中,函数是一等公民,定义一个函数f,...

  • Modern PHP : 闭包和匿名函数

    Modern PHP : 闭包和匿名函数

  • PHP闭包

    一. 闭包函数又叫做匿名函数(没有函数名称的函数). 英文closure 匿名函数常在js函数中出现,比如ajax...

  • PHP 闭包

    闭包和匿名函数在php5.3中引入,闭包是指的创建时封装周围状态的函数,即便闭包所在的环境不存在了,闭包中封装的状...

  • php闭包

    在公众号中看到闭包的概念,其实就是结合匿名函数的运用,稍微总结一下用法: 3中简单的闭包使用情况:* 在函数里定义...

  • PHP新特性之闭包、匿名函数

    闭包 闭包是什么? 1).闭包和匿名函数在PHP5.3中被引入。2).闭包是指在创建时封装函数周围状态的函数,即使...

  • PHP闭包实现

    闭包是指在创建时封装周围状态的函数。即使闭包所在的环境不在了,闭包中封装的状态依旧存在。注意在php中匿名函数=闭...

网友评论

      本文标题:PHP 闭包那些事儿

      本文链接:https://www.haomeiwen.com/subject/gevkqftx.html