PHP闭包的理解是使用

2019-02-25  本文已影响6人  云龙789

其实学习一个新的概念,除了知道怎么使用,更多的我是想知道它的使用场景。应用场景才是设计的根源。而对于PHP闭包的讲解,大多都是讲解的例子,但是只知道怎么用,还是不知道用在什么时候。这种情况你是不能灵活使用这个知识点的。

1.面向对象变成语言代码的复用主要采用继承来实现,而函数的复用,就是通过闭包来实现。这就是闭包的设计初衷。
2.闭包可以在函数里面访问指定域上午变量,在PHP里使用use关键字来实现。
3.php会自动把闭包函数转换成内置类 Closure 的对象实例,依赖 Closure 的对象实例又给闭包函数添加了更多的能力。
4.Closure::bind 复制一个闭包,绑定指定 this 对象和类作用域。
5.Closure::bindTo 复制当前闭包对象,绑定指定的 this对象和类作用域。

class Person
{
    public $name = 'test';

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return  $this->name;
    }
}

$closure = function () {
    return $this->name;
};

$person = new Person();
$bindTo =$closure->bindTo($person);
echo $bindTo(); //test
echo '<br>';
$bind = Closure::bind($closure,$person);
echo($bind());//test
echo '<br>';
$person->setName('new test');
echo $bindTo(); // 'new test'
echo '<br>';
echo($bind()); //'new test'
demo打印结果

注意

bindTo -- 是将当前闭包 bindTo(绑定到) 对象
bind -- 是将闭包绑定到对象,第一个参数是闭包,第二个参数是对象
Closure::bind Closure::bindTo 都是闭包的特性,而不是对象
bind 的第二个参数和 bindTo的第三个参数 newscope,是关联到匿名函数的类作用域,或者 'static' 保持当前状态。如果是一个对象,则使用这个对象的类型为心得类作用域。 这会决定绑定的对象的 保护、私有成员 方法的可见性。所以这个对象其实是 class 与 {} 中间的对象名,而不是实例化的那个变量。如果你是在对象中写,可以直接使用 CLASS 表示这个参数。如果不添加这个参数,则不能使用对应的 private、protect 方法或者属性

1.理论上闭包和匿名函数是不同的概念。不过,PHP将其视作相同的概念。所以在PHP语言中闭包其实就是匿名函数
2.PHP闭包和匿名函数的句法和普通函数相同,闭包和匿名函数其实是伪装成函数的对象,它们是Closure 类的实例。闭包和字符串或者整数一样,也是一等值类型。
3.我们之所以能够调用 $closure 变量,使用为这个变量的值是一个闭包,而且闭包对象实现了 _invole() 魔术方法,只要变量后有(),PHP就会查找并调用 _invoke() 方法

  1. PHP闭包是对象。与人任何其他PHP对象类似,每个闭包实例都可以使用 $this 关键字获取闭包的内部状态。闭包对象的默认状态没什么用,不过有一个 __invoke() 魔术方法和一个bindTo()方法,仅此而已
    5.但是,bindTo() 方法为闭包增加了一些有趣的潜力,我们可以使用这个方法把 Closure 对象的内部状态绑定到其他对象上,bindTo(),方法的第二个参数很重要,其作用是指定绑定闭包的那个对象所属的PHP类。因此,闭包可以访问绑定闭包的对象中收保护和私有的成员变量。
    6.你会发现,PHP框架经常使用bindTo()方法把路由URL映射到匿名回掉函数上。框架会把匿名函数绑定到应用对象上,这么做,可以在这个匿名函数中使用$this关键字引用重要的应用对象。
<?php

class App
{
    protected $routes = [];
    protected $responseBody;

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

    public function dispatch($currentPath)
    {
        foreach ($this->routes as $path => $callback) {
            if ($path == $currentPath) {
                echo $callback();
            }
        }
    }

    public function getResponse()
    {
        return $this->responseBody;
    }
}

$app = new App();
$app->addRoute('test', function () {
    $this->responseBody = 'test path';
});

$app->addRoute('name', function () {
    $this->responseBody = 'name path';
});

$app->dispatch('test');
echo $app->getResponse(); // test path
echo '<br>';
$app->dispatch('name');
echo $app->getResponse(); //test path


当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
也就是只要一个对象的变量(比如以下的$adder) 加上一个 (),其实就会调用 __invoke()方法。
而闭包,就相当于是 Closure 类的 __invoke() 方法

第一个参数是类的实例化,第二个参数是  __construct() 的参数,return 返回的结果是闭包中返回的结果。
demo 还是上面的那个

$callback = function(){
    return $this->responseBody = 'test path';

};
$app = new App();
$app->addRoute('test', $callback);

echo $callback->call($app);
<?php

class Add {
    public $left;
    public $right;

    public function construct($left = 0, $right = 0) {
        $this->left  = $left;
        $this->right = $right;
    }

    public function __invoke() {
        return $this->left + $this->right;
    }
}

$adder = new Add;

$adder->left  = 1;
$adder->right = 2;
echo $adder(); // 3

$adder->left  = 3;
echo $adder(); // 5
上一篇 下一篇

猜你喜欢

热点阅读