通过几个栗子认识 PHP 闭包

栏目: PHP · 发布时间: 5年前

内容简介:有收获的话请匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。匿名函数目前是通过 Closure 类来实现的。

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

  • 示例代码
  • 本文地址
  • 本人能力有限,如遇到什么不对的地方还望指出修正,谢谢
  • 所有栗子的输出都使用 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 ( 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 ( 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( newscope = 'static') { }

<?php
namespace PHP\Demo\Closure;

class ClosureBindTo
{
    public function __call($name, $arguments)
    {
        if (count($arguments) > 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 newthis, $newscope = 'static') { }

bind函数是bindTo的静态表示

<?php
namespace PHP\Demo\Closure;

class ClosureBind
{
    private $methods = [];

    public function addMethod(string $name, \Closure $callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException("第二个参数有误");
        }
        $this->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);
}

复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入浅出Ajax

深入浅出Ajax

(美)Brett McLaughlin / 东南大学出版社 / 2006-5 / 98.00元

本书将教会您如何在很短的时间内掌握使用JavaScript代码来向服务器提交异步请求?同时,您可以学习如何使用诸如动态HTML、XML、JSON、DOM等技术来解决开发过程中遇到的许多问题。让你从那些繁琐而笨拙的网站开发技术中彻底解放出来!本书将是一本指导您进行异步开发的经典参考书籍。   作为一名网站设计人员,您也许时常因为遇到以下情况而烦恼:用户只是移动了鼠标就要从服务器重载数据......一起来看看 《深入浅出Ajax》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具