PHP使用Closure创建匿名函数的方法介绍

PHP使用Closure创建匿名函数的方法介绍

Closure

用于代表匿名函数的类。

这个类不能实例化,里面主要有两个方法,都用来复制闭包,一个静态一个动态,下面分别详细讲解下这两个不好理解的方法。

Closure::bind

public static Closure Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] )

参数说明:
closure
需要绑定的匿名函数。

newthis
需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包。

newscope
想要绑定给闭包的类作用域,或者 'static' 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 
私有、保护方法 的可见性。 The class scope to which associate the closure is to be associated, or 'static' to keep the 
current one. If an object is given, the type of the object will be used instead. This determines the visibility of 
protected and private methods of the bound object.

参数说明:

  • closure需要绑定的匿名函数。

  • newthis需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包。

  • newscope想要绑定给闭包的类作用域,或者 'static' 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性。

上面是该方法的定义,

第一个参数很好理解,就是一个闭包函数;

第二个参数就不太好理解,如果要复制的闭包中包含$this,这个对象就表示这个$this,闭包函数里面对这个对象的修改在调用结束之后也会保持一致,比如修改了一个属性;

第三个参数就不太好理解了,看官方的说明也是云里雾里的,默认参数情况下,调用$this->访问object $newthis中的属性函数的时候,会有限制,只能访问public属性的函数,如果想访问protected/private属性,就要设置为对应的类名/类实例,就要像在类里面一样,要访问那个类的保护/私有属性函数。

例子

<?php
class T {
    private function show()
    {
        echo "我是T里面的私有函数:show\\n";
    }

    protected  function who()
    {
        echo "我是T里面的保护函数:who\\n";
    }

    public function name()
    {
        echo "我是T里面的公共函数:name\\n";
    }
}

$test = new T();

$func = Closure::bind(function(){
    $this->who();
    $this->name();
    $this->show();
}, $test);

$func();

上面的代码会报错Fatal error: Uncaught Error: Call to protected method T::who() from context 'Closure'。 加上bind第三个参数为t::class或者new T(),会正常输出每一个结果。

我是T里面的保护函数:who
我是T里面的公共函数:name
我是T里面的私有函数:show

当然了,闭包也可以传递参数

$test = new StdClass();
var_dump($test);

$func = Closure::bind(function($obj){
    $obj->name = "燕睿涛";
}, null);

$func($test);
var_dump($test);

上面的程序跟匿名函数一样,啥对象也没有依赖,上面的程序会输出:

object(stdClass)#1 (0) {
}
object(stdClass)#1 (1) {
  ["name"]=>
  string(9) "燕睿涛"
}

另外还有个特别要说明的例子

<?php
class T {
    private function show()
    {
        echo "我是T里面的私有函数:show\\n";
    }

    protected  function who()
    {
        echo "我是T里面的保护函数:who\\n";
    }

    public function name()
    {
        echo "我是T里面的公共函数:name\\n";
    }
}

$func = Closure::bind(function ($obj) {
    $obj->show();
}, null);

$test = new T();

$func($test);

上面的情况会输出什么呢,没错,会报错,提示访问不了私有属性show,这个时候,加上第三个参数就可以了,看了第三个参数不光影响$this的作用域,
也可以影响参数的作用域。

Closure::bindTo

bindTobind功能类似,这里只是另外一种形式,都是复制当前闭包对象,绑定指定的$this对象和类作用域。,参数比bind少了第一个,
后面两个一样,当然还有一个区别就是bindTo不是静态方法,是闭包才会存在的一个属性方法。

例子

<?php
class T {
    private function show()
    {
        echo "我是T里面的私有函数:show\\n";
    }

    protected  function who()
    {
        echo "我是T里面的保护函数:who\\n";
    }

    public function name()
    {
        echo "我是T里面的公共函数:name\\n";
    }
}

$func = function () {
    $this->show();
    $this->who();
    $this->name();
};

$funcNew = $func->bindTo(new T(), T::class);

$funcNew();

上面函数的输出和bind的类似

我是T里面的私有函数:show
我是T里面的保护函数:who
我是T里面的公共函数:name

一个trick

这个函数是在看composer生成的自动加载源码的时候碰到的,在composer中用的比较特别,下面是截取部分composer中的代码

// 文件autoload_real.php
call_user_func(\\Composer\\Autoload\\ComposerStaticInit898ad46cb49e20577400c63254121bac::getInitializer($loader));

// 文件autoload_static.php
public static function getInitializer(ClassLoader $loader)
{
    return \\Closure::bind(function () use ($loader) {
        $loader->prefixLengthsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixLengthsPsr4;
        $loader->prefixDirsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixDirsPsr4;
        $loader->prefixesPsr0 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixesPsr0;
        $loader->classMap = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$classMap;

    }, null, ClassLoader::class);
}

上面的代码比较奇特,在call_user_func中,第一感觉是传错参数了,其实不然,这里调用了一个函数,这个函数会返回一个Closure对象,
也就是一个匿名函数,最终传入的参数还是一个callable类型。再看看这个返回的闭包,里面使用了use,这是连接闭包和外部变量的桥梁。
至于这里为什么普通传参数就可以,是因为php5里面,对象形参和实参数指向相同的对象,函数里面对对象的修改会反映到对象外面。

所以,上面这么做是没问题的,还有另外一种形式也可以

call_user_func(\\Composer\\Autoload\\ComposerStaticInit898ad46cb49e20577400c63254121bac::getInitializer(), $loader);

public static function getInitializer()
{
    return \\Closure::bind(function ($loader) {
        $loader->prefixLengthsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixLengthsPsr4;
        $loader->prefixDirsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixDirsPsr4;
        $loader->prefixesPsr0 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixesPsr0;
        $loader->classMap = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$classMap;

    }, null, ClassLoader::class);
}

总结

好长时间没写blog了,有时候太烦躁,静不下心来,有时又有没有找到想写的东西。还是得静下心来,好好做好每一件事,遇事情不要烦躁,心放大,心平气和的处理每一件事。

关于PHP使用Closure创建匿名函数的方法介绍的文章就分享到这,如果对你有帮助欢迎继续关注我们哦

本文来自投稿,不代表重蔚自留地立场,如若转载,请注明出处https://www.cwhello.com/40506.html

如有侵犯您的合法权益请发邮件951076433@qq.com联系删除

(0)
php学习php学习订阅用户
上一篇 2022年6月13日 23:28
下一篇 2022年6月13日 23:28

相关推荐

  • 如何用PHP获取referer判断来路防止非法访问

    本篇文章给大家介绍如何用PHP获取referer判断来路防止非法访问?有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。下载页面down.php 的php代码 现在我发现,用迅雷,谷歌浏览器直接打开,就能输出…

    2023年3月29日
    08
  • PHP 新手入门之数据类型

    标量数据类型:是数据结构中最基本单元,只能储存一个数据 布尔型:boolean 字符串型:string 浮点型: float 整型 : integer 两种复合类型: array() 数组 object 对象 俩种特殊类型 resource 资源型 null 空 判…

    2018年12月16日
    0273
  • php获取一些时间实现方法(附代码)

    这几天在开发的时候遇到的一些时间上的问题,整理了一下,分享给大家,可以看看,有需要的话可以利用一下。 1.获取上个月第一天及最后一天. echo date('Y-m-01', strtotime('-1 month')); echo "<br/>"; echo…

    2018年4月25日
    0185
  • PHP实现Redis主从复制自动切换的方法。

    Redis是一款非常流行的键值对存储数据库,在现代Web应用中扮演着至关重要的角色。为了保证Redis的高可用性和稳定性,通常需要使用主从复制的技术。同时,由于主节点故障时需要自动切换到备用节点,使得复制集群具有…

    2023年5月21日
    013
  • 使用PHP和Redis实现自动补全搜索。

    在现代网站开发中,搜索功能是必不可少的。但是,当用户开始输入查询关键词时,搜索引擎通常会等待用户输入完成,然后执行一次完整的搜索。这会降低用户体验和响应速度,特别是在拥有大量数据的情况下。为了提高用…

    2023年5月21日
    01
  • 最简洁的PHP生成指定长度随机数的方法

    刚才在写短信验证码模块,需要用到指定位数的随机数,然后网上一找发现太可怕了这么简单的事情竟然用了好几十行多个循环嵌套……看来没有好脑仁儿真的不适合当程序员。自写了一行版本:function generate_code($lengt…

    2022年6月11日
    0202
  • 直击php中static,const与define的使用区别

    define部分:宏不仅可以用来代替常数值,还可以用来代替表达式,甚至是代码段。(宏的功能很强大,但也容易出错,所以其利弊大小颇有争议。)宏的语法为:#define 宏名称 宏值作为一种建议和一种广大程序员共同的习…

    2022年6月17日
    0134
  • PHP实现邮件异步发送的技术。

    随着电子邮件在我们日常生活和工作中的广泛使用,许多网站和应用程序都需要发送大量的电子邮件。然而,在大量邮件发送的情况下,同步发送可导致网站的性能下降,因为PHP必须等待邮件发送完成才能继续运行。为了避免…

    2023年5月23日
    05

联系我们

QQ:951076433

在线咨询:点击这里给我发消息邮件:951076433@qq.com工作时间:周一至周五,9:30-18:30,节假日休息