资讯专栏INFORMATION COLUMN

通过几个栗子认识 PHP 闭包

马忠志 / 1924人阅读

摘要:复制一个闭包,绑定指定的对象和类作用域。匿名函数目前是通过类来实现的。

通过几个栗子认识PHP闭包

一、栗子1 用作于回调

二、栗子2 用作于变量赋值

三、栗子3 从父作用域继承变量

四、栗子4的前提条件,简单理解call_user_func_array()call_user_func()方法

1. call_user_func — 把第一个参数作为回调函数调用

2. call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数

五、栗子4 绑定闭包在指定对象

1. Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。

2. Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。

六、参考资料

有收获的话请加颗小星星,没有收获的话可以 反对 没有帮助 举报三连

示例代码

本文地址

本人能力有限,如遇到什么不对的地方还望指出修正,谢谢

所有栗子的输出都使用symfony/var-dumpe美化了

匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。

匿名函数目前是通过 Closure 类来实现的。

一、栗子1 用作于回调
$rs = preg_replace_callback("/-([a-z])/", function ($match) {
    return strtoupper($match[1]);
}, "hello-world");

dump($rs); // "helloWorld"
二、栗子2 用作于变量赋值
$greet = function ($name) {
    dump($name);
};

dump($greet instanceof Closure); // true
$greet("PHP"); // "PHP"
三、栗子3 从父作用域继承变量
$message = "hello";
$example = function () use ($message) {
    dump($message);
};
dump($example instanceof Closure); // true
$example(); // "hello"
四、栗子4的前提条件,简单理解call_user_func_array()call_user_func()方法 1. call_user_func — 把第一个参数作为回调函数调用

function call_user_func ($function, ...$parameter) {}

该方法接收多个参数,第一个就是回调函数,可以是普通函数,也可以是闭包函数,后面的多个参数都是作为函数回调使用

$rs = call_user_func(function (...$params) {
    return func_get_args();
}, 1, 2, 3);
dump($rs); // [1,2,3]
2. call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数

function call_user_func_array ($function, array $param_arr) {}

该方法接收2个参数,第一个就是回调函数,可以是普通函数,也可以是闭包函数,后面的数组参数都是作为函数回调使用

$rs = call_user_func_array(function (array $params) {
    return func_get_args();
}, [1, 2, 3]);
dump($rs); // [1,2,3]
五、栗子4 绑定闭包在指定对象

楼主见解是将方法绑定到指定类上,使得方法也可以使用类的属性和方法,非常适合配合__call()魔术方法和call_user_func_array方法一起使用

1. Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。

function bindTo($newthis, $newscope = "static") { }

 1 && $arguments[0] instanceof Closure) {
            return call_user_func_array($arguments[0]->bindTo($this), array_slice($arguments, 1));
        }
        throw new InvalidArgumentException("没有这个方法");
    }
}

// 测试
public function testClosureBindTo()
{
    $obj = new ClosureBindTo();
    $this->assertEquals(2, $obj->add(function (array $params) {
        return ++$params[0];
    }, [1]));

    // 测试同一个实例
    $newObj = $obj->test(function (array $params){
        return $this;
    }, [1]);
    $this->assertTrue($newObj instanceof $obj);
}
2. Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。

static function bind(Closure $closure, $newthis, $newscope = "static") { }

bind函数是bindTo的静态表示

methods[$name] = Closure::bind($callback, $this, get_class());
    }

    public function __call(string $name, array $arguments)
    {
        if (isset($this->methods[$name])) {
            return call_user_func_array($this->methods[$name], $arguments);
        }

        throw new RuntimeException("不存在方法[{$name}]");
    }
}

// 测试
public function testClosureBind()
{
    $obj = new ClosureBind();
    $obj->addMethod("add", function (array $params) {
        return ++$params[0];
    });
    $this->assertEquals(2, $obj->add([1]));

    // 测试同一个实例
    $obj->addMethod("test", function (array $params) {
        return $this;
    });
    $this->assertTrue($obj->test([1]) instanceof $obj);
}
六、参考资料

php手册

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29847.html

相关文章

  • [学习笔记] JavaScript 闭包

    摘要:但是,必须强调,闭包是一个运行期概念。通过原型链可以实现继承,而与闭包相关的就是作用域链。常理来说,一个函数执行完毕,其执行环境的作用域链会被销毁。所以此时,的作用域链虽然销毁了,但是其活动对象仍在内存中。 学习Javascript闭包(Closure)javascript的闭包JavaScript 闭包深入理解(closure)理解 Javascript 的闭包JavaScript ...

    sunsmell 评论0 收藏0
  • JS基础知识:变量对象、作用域链和闭包

    摘要:前言这段时间一直在消化作用域链和闭包的相关知识。而作用域链则是这套规则这套规则的具体运行。是变量对象的缩写那这样放有什么好处呢我们知道作用域链保证了当前执行环境对符合访问权限的变量和函数的有序访问。 前言:这段时间一直在消化作用域链和闭包的相关知识。之前看《JS高程》和一些技术博客,对于这些概念的论述多多少少不太清楚或者不太完整,包括一些大神的技术文章。这也给我的学习上造成了一些困惑,...

    Keven 评论0 收藏0
  • “动静结合” 小白初探静态(词法)作用域,作用域链与执行环境(EC)

    摘要:图片中的作用域链,是全局执行环境中的作用域链。然后此活动对象被推入作用域链的最前端。在最后调用的时候,创建先构建作用域链,再创建执行环境,再创建执行环境的时候发现了一个变量标识符。 从图书馆翻过各种JS的书之后,对作用域/执行环境/闭包这些概念有了一个比较清晰的认识。 栗子说明一切 第一个栗子 来看一个来自ECMA-262的栗子: var x = 10; (function foo(...

    Drummor 评论0 收藏0
  • JavaScript基础系列---闭包及其应用

    摘要:所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。所以本文中将以维基百科中的定义为准即在计算机科学中,闭包,又称词法闭包或函数闭包,是引用了自由变量的函数。 闭包(closure)是JavaScript中一个神秘的概念,许多人都对它难以理解,我也一直处于似懂非懂的状态,前几天深入了解了一下执行环境以及作用域链,可戳查看详情,而闭包与作用域及作用域链的关系密不可分,所...

    leoperfect 评论0 收藏0
  • Laravel 服务容器实现原理

    摘要:框架中就是使用服务容器来实现控制反转和依赖注入。容器依赖注入的实现实现原理需要了解的知识点闭包匿名函数匿名函数,也叫闭包函数,允许临时创建一个没有指定名称的函数反射以上版本具有完整的反射,添加了对类接口函数方法和扩展进行反向工程的能力。 前言 通过实现laravel 框架功能,以便深入理解laravel框架的先进思想。 什么是服务容器 服务容器是用来管理类依赖与运行依赖注入的工具。La...

    wupengyu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<