在PHP中如何为匿名函数指定this?
在之前的文章中,我们已经学习过匿名函数的使用,没有看过的小伙伴可以进入传送门先去了解下闭包匿名函数的用法,传送:还不知道PHP有闭包?那你真OUT了。
关于闭包匿名函数,在JS中有个很典型的问题就是要给它绑定一个 this 作用域。其实这个问题在PHP中也是存在的,比如下面这段代码:
$func = function($say){
echo $this->name, ':', $say, PHP_EOL;
};
$func('good'); // Fatal error: Uncaught Error: Using $this when not in object context
在这个匿名函数中,我们使用了 \$this->name 来获取当前作用域下的 $name 属性,可是,这个 $this 是谁呢?我们并没有定义它,所以这里会直接报错。错误信息是:使用了 $this 但是没有对象上下文,也就是说没有指定 $this 引用的作用域。
bindTo() 方法绑定 $this
好吧,那么我们就给它一个作用域,和 JS 一样,使用一个 bindTo() 方法即可。
$func1 = $func->bindTo($lily, 'Lily');
// $func1 = $func->bindTo($lily, Lily::class);
// $func1 = $func->bindTo($lily, $lily);
$func1('cool');
这回就可以正常输出了。 bindTo() 方法是复制一个当前的闭包对象,然后给它绑定 $this 作用域和类作用域。其中, $lily 参数是一个 object $newthis 参数,也就是给这个复制出来的匿名函数指定 $this 。而第二个参数 'Lily' 则是绑定一个新的 类作用域 ,它代表一个类型、决定在这个匿名函数中能够调用哪些 私有 和 受保护 的方法,上例中给出的三种方式都可以用来定义这个参数。如果不给这个参数,那么我们就不能访问这个 private 的 $name 属性了:
$func2 = $func->bindTo($lily);
$func2('cool2'); // Fatal error: Uncaught Error: Cannot access private property Lily::$name
call() 方法绑定 $this
在PHP7以后,PHP新增加了 call() 方法来进行匿名函数的 $this 绑定,我们来看看它和 bindTo() 方法有哪些区别。
$func->call($lily, 'well'); // Lily:well
额......
是不是感觉方便好多。首先,它直接执行了,不需要再赋值给一个变量,也就是说,它不是去复制那个闭包函数的而是直接执行了;其次,没有 类作用域 这个概念了,第一个参数还是指定新的 $this 的指向,而后面的参数就是原来闭包函数的参数。
虽然很方便,但是它也带来了另一个问题,因为没有 类作用域 的限制,所以会破坏封装。你好不容易做好的面向对象的设计,封装了一堆属性,然后使用这个 call() 就让对象的所有 私有 和 受保护 内容都暴露了出来。当然,这也是看我们自己的业务情况了,毕竟两种形式我们在写代码的时候都是可以自由选择的。
总结
其实包括闭包函数在内,这些特性都非常像JS。这也是语言融合的一种趋势,不管是学习了JS来看PHP的这些特性还是先学了PHP再去看JS,都会让我们更容易理解它们的作用与能力,这就是语言特性融合带来的好处。不管怎么样,学就是了,继续加油吧!!
参考文档:
https://www.php.net/manual/zh/functions.anonymous.php
https://www.php.net/manual/zh/closure.bindto.php
https://www.php.net/manual/en/closure.call.php
在PHP中如何为匿名函数指定this?的更多相关文章
- Java中的lambda匿名函数使用
Java中的lambda匿名函数使用 lambda匿名函数的使用是为了满足某些情况下需要临时定义函数,或者事先定义,需要时才使用.在python里面,lambda表达式的表达方式为:lambda 参数 ...
- js 函数中的 return+匿名函数
今天一个刚学js的朋友给了我一段代码问为什么方法不执行,代码如下: 代码如下: function makefunc(x) { return function (){ return x; } } ...
- C#中委托,匿名函数,lamda表达式复习
一.委托 1.就给类比较,类用class声明,委托用delegate声明. 2.委托要指向一个真正的方法. 3.委托的签名,要和指向的方法一样. //1.声明一个委托 public delegate ...
- C#中委托、匿名函数、Lambda表达式的一些个人理解
0x01定义一个委托,相当于定义一个可以存储方法的特殊变量类型 下面我们看具体的代码,通过代码更好理解 delegate void IntMethodInvoker(int x); 这行代码就是声明一 ...
- .net 中写 psql 匿名函数、过程语言
DO --关键字 $serch$ --$中间随便写, 不能用特殊符号和数字好像$ DECLARE times integer; --定义变量 rec history_depart%ROWTYPE; - ...
- Java中的Lambda匿名函数后续
函数式编程(函数式接口):一个接口只包含一个方法实现 public interface Lambda{ void method(); } // 调用 Lambda lambda = new Lambd ...
- python之匿名函数以及在内置函数中的使用
一. 匿名函数 Python使用 lambda 来创建匿名函数.所谓匿名函数,它与用 def 关键字定义的函数相比,没有函数名称. 1.1 匿名函数定义及特点 语法: lambda [para1, p ...
- Python中的匿名函数lambda的用法
一.lambda函数的简介 对lambda函数,它其实是一个类似于def的函数,只不过lambda是一个不需要定义函数名的匿名函数.当我们在有些时候,需要做一些简单的数学计算时,如果定义一个def函 ...
- python中匿名函数lambda如何用
python中经常用到的一个函数:匿名函数lambda ,什么是匿名函数?匿名函数的意义是什么?匿名函数怎么样用?(疑问三连,what,why,how) 一,什么是匿名函数? python中没有名字的 ...
随机推荐
- Git-07-分支管理
创建与合并分支 为什么要创建分支? 假设你准备开发一个新功能,但是需要两周才能完成, 第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了. 如果等代码全部写完 ...
- Golang语言系列-09-接口
接口 接口的定义和实现 package main import "fmt" /* [接口] 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现 ...
- pikachu CSRF
CSRF简介 CSRF 是 Cross Site Request Forgery 的 简称,中文名为跨域请求伪造在CSRF的攻击场景中,攻击者会伪造一个请求(一般是一个链接)然后欺骗目标用户进行点击, ...
- NOIP 模拟 $36\; \rm Dove 打扑克$
题解 \(by\;zj\varphi\) 引理 对于一个和为 \(n\) 的数列,不同的数的个数最多为 \(\sqrt n\) 证明: 一个有 \(n\) 个不同的数的数列,和最小就是 \(n\) 的 ...
- 常用正则表达式最强汇总(含Python代码举例讲解+爬虫实战)
大家好,我是辰哥~ 本文带大家学习正则表达式,并通过python代码举例讲解常用的正则表达式 最后实战爬取小说网页:重点在于爬取的网页通过正则表达式进行解析. 正则表达式语法 Python的re模块( ...
- ITIL学习笔记——ITIL入门小知识
1. 什么是ITIL? ITIL即IT基础架构库(Information Technology Infrastructure Library)由英国政府部门CCTA(Central Computing ...
- C#基础知识---动态为类型添加属性
一.概述 通常情况下,我们是事先在类型中定义好属性的,但有时候,我们需要动态为一个类型添加某些属性,这个时候,我们就需要使用DynamicObject类型了. 二.Demo using System; ...
- 信号量-Semaphore、SemaphoreSlim
核心类:Semaphore,通过int数值来控制线程个数. * 通过观察构造函数 public Semaphore(int initialCount, int maximumCount);: * in ...
- Spring详解(十)加载配置文件
在项目中有些参数经常需要修改,或者后期可能会有改动时,那我们最好把这些参数放到properties文件中,在源代码中读取properties里面的配置,这样后期只需要改动properties文件即可, ...
- Java File常见用法
一.构造方法 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例. File(String pathname) 通过将给定的路径名字符 ...