0

0

解析PHP闭包及Clourse类方法的作用

藏色散人

藏色散人

发布时间:2022-02-05 04:00:32

|

5057人浏览过

|

来源于juejin

转载

PHP Clourse(闭包类) 浅析

0x00 前言

闭包是指在创建时封装周围状态的函数。即使闭包所在的环境不存在了,闭包中封装的状态依然存在。

在 PHP 里所有的闭包都是 Clourse 类所实例化的一个对象,也就是说闭包与其他 PHP 对象没有什么不同。而一个对象就必然有其方法和属性,这篇文章将总结 PHP 中闭包的基础用法和 Clourse 类方法的作用。【推荐:PHP视频教程

0x01 闭包基本用法

下面看看最基本的闭包使用方法:

立即学习PHP免费学习笔记(深入)”;

嘿,这段代码最直观的感受就是将一个函数赋值给了 $hello 变量,然后通过 $hello 直接调用它。但是这个闭包并没有从父作用域中继承变量(就是封装周围状态),我们可以通过 use 关键字从闭包的父作用域继承变量。示例如下:

PHP 7.1 起,use 不能传入此类变量: superglobals、 $this 或者和参数重名。

此外在使用 use 关键字时,父作用域的变量是通过值传递进闭包的。也就是说一旦闭包创建完成,外部的变量即使修改也不会影响传递进闭包内的值(就是即使闭包所在的环境不存在了,闭包中封装的状态依然存在)。示例如下:

传递变量的引用可以使闭包修改外部变量的值,示例如下:

注意:PHP 中传递对象时,默认是以引用传递所以在闭包内操作 use 传递的对象时需要特别注意。示例如下:

name = 'Lai Fu';
};
$changeName();
echo $dog->name;
// 输出 Lai Fu

0x02 Clourse 类

证明闭包只是 Clourse 类对象

上面的代码将输出 Closure 证明了闭包只是一个普通的 Closure 类对象。

Clourse 类摘要

我们可以从 PHP 官方手册 看到闭包类的相关信息,下面是我在 PhpStorm 的本地文档查看到 Clourse 类摘要。

/**
 * Class used to represent anonymous functions.
 * 

Anonymous functions, implemented in PHP 5.3, yield objects of this type. * This fact used to be considered an implementation detail, but it can now be relied upon. * Starting with PHP 5.4, this class has methods that allow further control of the anonymous function after it has been created. *

Besides the methods listed here, this class also has an __invoke method. * This is for consistency with other classes that implement calling magic, as this method is not used for calling the function. * @link http://www.php.net/manual/en/class.closure.php */ final class Closure { /** * This method exists only to disallow instantiation of the Closure class. * Objects of this class are created in the fashion described on the anonymous functions page. * @link http://www.php.net/manual/en/closure.construct.php */ private function __construct() { } /** * This is for consistency with other classes that implement calling magic, * as this method is not used for calling the function. * @param mixed $_ [optional] * @return mixed * @link http://www.php.net/manual/en/class.closure.php */ public function __invoke(...$_) { } /** * Duplicates the closure with a new bound object and class scope * @link http://www.php.net/manual/en/closure.bindto.php * @param object $newthis The object to which the given anonymous function should be bound, or NULL for the closure to be unbound. * @param mixed $newscope 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. * @return Closure Returns the newly created Closure object or FALSE on failure */ function bindTo($newthis, $newscope = 'static') { } /** * This method is a static version of Closure::bindTo(). * See the documentation of that method for more information. * @static * @link http://www.php.net/manual/en/closure.bind.php * @param Closure $closure The anonymous functions to bind. * @param object $newthis The object to which the given anonymous function should be bound, or NULL for the closure to be unbound. * @param mixed $newscope 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. * @return Closure Returns the newly created Closure object or FALSE on failure */ static function bind(Closure $closure, $newthis, $newscope = 'static') { } /** * Temporarily binds the closure to newthis, and calls it with any given parameters. * @link http://php.net/manual/en/closure.call.php * @param object $newThis The object to bind the closure to for the duration of the call. * @param mixed $parameters [optional] Zero or more parameters, which will be given as parameters to the closure. * @return mixed * @since 7.0 */ function call ($newThis, ...$parameters) {} /** * @param callable $callable * @return Closure * @since 7.1 */ public static function fromCallable (callable $callable) {} }

首先 Clourse 类为 final 类,也就是说它将无法被继承,其次它的构造函数 __construct 被设为 private 即无法通过 new 关键字实例化闭包对象,这两点保证了闭包只能通过 function (...) use(...) {...} 这种语法实例化 。

为什么闭包可以当作函数执行?

从上面的类摘要中我们看出 Clourse 类实现了 __invoke 方法,在 PHP 官方手册中对该方法解释如下:

PHP5学习对象教程
PHP5学习对象教程

PHP5学习对象教程由美国人古曼兹、贝肯、瑞桑斯编著,简张桂翻译,电子工业出版社于2007年12月1日出版的关于PHP5应用程序的技术类图书。该书全面介绍了PHP 5中的新功能、编程方法及设计模式,还分析阐述了PHP 5中新的数据库连接处理、错误处理和XML处理等机制,帮助读者系统了解、熟练掌握和高效应用PHP。

下载

当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。

这就是闭包可以被当作函数执行的原因。

绑定指定的$this对象和类作用域

在允许使用闭包路由的框架中(如:Slim),我们可以看见如下写法:

$app->get('/test', function () {
    echo $this->request->getMethod();
});

在一个闭包居然能中使用 $this?这个 $this 指向哪个对象?

通过 bindTo 和 bind 方法都能够实现绑定 $this 和类作用域的功能,示例如下:

num . PHP_EOL;
};
$newAdd1 = $add->bindTo($pandas);
$newAdd1();
// 输出 2
$newAdd2 = Closure::bind($add, $pandas);
$newAdd2();
// 输出 3

上面的这段例子将指定对象绑定为闭包的 $this,但是我们并没有指定类作用域。所以如果将 Pandas 类的 $num 属性改写为 protected 或 private 则会抛出一个致命错误!

Fatal error: Uncaught Error: Cannot access protected property Pandas::$num

在需要访问绑定对象的非公开属性或方法时,我们需要指定类作用域,示例如下:

num . PHP_EOL;
};
$newAdd1 = $add->bindTo($pandas, $pandas);
$newAdd1();
// 输出 2
$newAdd2 = Closure::bind($add, $pandas, 'Pandas');
$newAdd2();
// 输出 3

这里我们看见 bindTo 和 bind 方法都指定了 $newscope 参数,$newscope 参数默认为 static 即不改变类作用域。$newscope 参数接受类名或对象,并将闭包的类作用域改为指定的类作用域,此时 Pandas 类的 $num 属性便能够被闭包访问。

一次性绑定 $this 对象和类作用域并执行(PHP7)

bindTo 和 bind 方法每次指定新的对象和类作用域时都要将原闭包进行复制然后返回新的闭包,在需要多次修改绑定对象的情景下便显得繁琐,所以 PHP7 提供了一个新的方法 call 它能将闭包临时的绑定到一个对象中(类作用域同时被修改为该对象所属的类)并执行。示例如下:

num += $num;
    echo $this->num . PHP_EOL;
};
$add->call($pandas, 5);
// 输出 6

Callable 转为闭包(PHP7.1)

在 PHP7.1 中 Closure 类存在 fromCallable 方法能够将 callable 类型的值转为闭包,示例如下:

这种写法还是挺爽的毕竟通过闭包调用总比用 call_user_func 函数调用爽的多^_^。

0x03 总结

更多相关内容请看 Closure 类 和 匿名函数,因为 PHP 官方手册中文版的 Closure 类没有更新,所以没有 call 和 fromCallable 方法的内容,推荐大家看英文版(ㄒoㄒ)。

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2832

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1696

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1556

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

1058

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1505

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1256

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1609

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1307

2023.11.13

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 9.2万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 10.4万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号