PHP闭包的理解是使用

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

  • 以下总结来自于上面推荐文章的总结,但是我觉得是有道理的

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

  • demo.php
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 方法或者属性

  • Moderm PHP 对比包的讲解

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(); //namepath
  • dispatch 方法使用以下方式更好
   public function dispatch($currentPath)
    {
        if (array_key_exists($currentPath,$this->routes)){
            echo $this->routes[$currentPath]();
        }
    }

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

  • Closure::call function call ($newThis, ...$parameters) {}
    Closure::call — Binds and calls the closure(绑定一个类,并返回闭包) ----- PHP>=7.0
第一个参数是类的实例化,第二个参数是  __construct() 的参数,return 返回的结果是闭包中返回的结果。
demo 还是上面的那个

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

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

echo $callback->call($app);
  • _invoke() 魔术方法的使用
<?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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269