PHP Closure创建匿名函数
Closure 类
用于代表匿名函数的类。
匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象。在过去,这个类被认为是一个实现细节,但现在可以依赖它做一些事情。自 PHP 5.4 起,
这个类带有一些方法,允许在匿名函数创建后对其进行更多的控制。
这个类不能实例化,里面主要有两个方法,都用来复制闭包,一个静态一个动态,下面分别详细讲解下这两个不好理解的方法。
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.
上面是该方法的定义,第一个参数很好理解,就是一个闭包函数;第二个参数就不太好理解,如果要复制的闭包中包含$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
bindTo
和bind
功能类似,这里只是另外一种形式,都是复制当前闭包对象,绑定指定的$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了,有时候太烦躁,静不下心来,有时又有没有找到想写的东西。还是得静下心来,好好做好每一件事,遇事情不要烦躁,心放大,心平气和的处理每一件事。
写到最后,忽然想起高中的时候,刚好是5.12汶川大地震的时候,我们在西安,大地震过后还不停的会有余震,稍微一有余震,大家就都慌了,一窝蜂的往下冲,我没记错的话我们是在5楼,
直到一次我们物理老师来上课,这个老师年龄偏大,是市里面的特级教师(恩,应该没错),正好碰到余震,大家又疯了似得准备往外跑,这个时候老师说了一句话,让我至今
难忘,命在骨子里,这种余震没必要这么慌挤下去,命硬的怎么都没事
,确实,这种小余震挤下去可能更容易发生事故,虽然这句话带了少许的消极,但里面更多的是心态的平静、
心比较大、冷静果断的体现,这是我要学习的。
该出现的总会出现,不该出现的永远不会出现,一味的好高骛远,追求太远的目标容易导致焦虑,当然要不要妄自菲薄,总之一句话:心平气和、心放大、切勿患得患失、
踏踏实实的做好每一件事,越努力、越幸运,越幸运、越努力。
PHP Closure创建匿名函数的更多相关文章
- 闭包(Closure)和匿名函数(Anonymous function)/lambda表达式的区别
闭包(Closure)和匿名函数(Anonymous function)/lambda表达式的区别 函数最常见的形式是具名函数(named function): function foo(){ con ...
- python基础练习题(题目 使用lambda来创建匿名函数。)
day34 --------------------------------------------------------------- 实例049:lambda 题目 使用lambda来创建匿名函 ...
- lambda创建匿名函数
1)print map(lambda x: x + 1, [y for y in range(10)]) 输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]map(lambda &l ...
- 【python】lambda创建匿名函数
- php匿名函数和闭包函数及use关键字传参及Closure匿名函数类
php闭包函数用use传参有什么意义?答:use引用外层变量,比如全局变量 Closure,匿名函数,是php5.3的时候引入的,又称为Anonymous functions.字面意思也就是没有定义名 ...
- Go匿名函数
1.GO语言的匿名函数就是闭包 基本概念 闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义.要执行的代码块(由于自由变 ...
- [Python Study Notes]匿名函数
Python 使用 lambda 来创建匿名函数. lambda这个名称来自于LISP,而LISP则是从lambda calculus(一种符号逻辑形式)取这个名称的.在Python中,lambda作 ...
- 12_Python的(匿名函数)Lambda表达式_Python编程之路
Python作为一门高级语言,与很多编程语言一样都具有匿名函数这一特征 匿名函数,也就Lambda表达式,通俗来讲就是不用命名的方法,直接定义,直接用即可 创建匿名函数需要用到Lambda关键字,下面 ...
- Python高阶函数和匿名函数
高阶函数:就是把函数当成参数传递的一种函数:例如 注解: 1.调用add函数,分别执行abs(-8)和abs(11),分别计算出他们的值 2.最后在做和运算 map()函数 python内置的一个高阶 ...
随机推荐
- bitmap 加载的时候出现OOM,nullpointer
1.OOM :对图片进行压缩,效果还不错:http://182.92.150.15:9876/static/server/topic_user/8068/201506/e5b37fec-0919-11 ...
- Android布局及属性归总(查询用)
常见布局 LinearLayout 线性布局 子元素任意,组织成一个单一的水平或垂直行,默认为水平方向TableLayout 表格布局 子元素为<Tabl ...
- Struts2命令空间小结
sturts2命名空间小结,以tomcat为服务器 1. 命名空间配置为“/” <package name="default" namespace="/" ...
- hibernate-Maven
1.创建Maven 2.创建Maven工程 3.然后一直下一步 4.创建成功后Maven 5.下载jra包 //hibernate <dependencies> <dependenc ...
- IOS Cell 重影
效果:重影 原因: 多次创建控件元素 解决:在initWithStyle中进行初始化元素
- OC纯代码全手工打造ScroolView实现翻页
OC纯代码全手工打造ScroolView实现翻页 1. 概述 分为三部分: 上部标题ScrollView 下部内容ScrollView 上部当前页 标示线 2. 效果 上下两部分都随着手势的滑动一块滑 ...
- freemarker配置,使用
最近在项目中用到freemarker,总是报一些莫名其妙的错误. 调查得知是由于在配置文件中属性[tag_syntax]的设置问题,我们的环境下该属性(auto_detect)默认设置了自动检测,也就 ...
- linux apache 打模块示例
主要是为了以后能举一反三 Apache配置方案 首先,安装apache的一个第三方模块“mod_rpaf”, 官方网站: http://stderr.net/apache/rpaf/ wget htt ...
- 使用AngularJS的三个重要原因
入门教程:http://www.ituring.com.cn/minibook/303 : http://angularjs.cn/tag/AngularJS 原因一:Google开发的框架 要知道开 ...
- 游戏开发之在UE4中编写C++代码控制角色
当你运行我们上次做完的项目,你可能会意识到我们移动的摄像机还是默认的那个摄像机,这个默认的摄像机可以自由飞翔.这一节,我们要使得开始的角色是我们的一个Avatar类的实例对象,并且使用键盘控制我们的角 ...