文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

PHP闭包及Clourse类的作用是什么

2023-06-29 02:21

关注

今天小编给大家分享一下PHP闭包及Clourse类的作用是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

PHP Clourse(闭包类) 浅析

0x00 前言

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

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

0x01 闭包基本用法

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

<?php$hello = function ($word) {    return 'hello ' . $word;};echo $hello('world');// 输出 hello world

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

<?php$name = 'panda';$hello = function () use ($name) {    return 'hello ' . $name;};echo $hello();// 输出 hello panda

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

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

<?php$name = 'panda';$hello = function () use ($name) {    return 'hello ' . $name;};$name = 'cat';echo $hello();// 输出 hello panda

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

<?php$name = 'panda';$changeName = function () use (&$name) {    $name = 'cat';};$changeName();echo $name;// 输出 cat

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

<?phpclass Dog {    public $name = 'Wang Cai';}$dog = new Dog();$changeName = function () use ($dog) {    $dog->name = 'Lai Fu';};$changeName();echo $dog->name;// 输出 Lai Fu

0x02 Clourse 类

证明闭包只是 Clourse 类对象

<?php$clourse = function () {    echo 'hello clourse';};if (is_object($clourse)) {    echo get_class($clourse);}// 输出 Closure

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

Clourse 类摘要

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

final class Closure {        private function __construct() { }        public function __invoke(...$_) { }        function bindTo($newthis, $newscope = 'static') { }        static function bind(Closure $closure, $newthis, $newscope = 'static') { }        function call ($newThis, ...$parameters) {}            public static function fromCallable (callable $callable) {}}

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

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

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

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

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

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

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

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

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

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

<?phpclass Pandas {    public $num = 1;}$pandas = new Pandas();$add = function () {    echo ++$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

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

<?phpclass Pandas {    protected $num = 1;}$pandas = new Pandas();$add = function () {    echo ++$this->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 它能将闭包临时的绑定到一个对象中(类作用域同时被修改为该对象所属的类)并执行。示例如下:

<?phpclass Pandas {    protected $num = 1;}$pandas = new Pandas();$add = function ($num) {    $this->num += $num;    echo $this->num . PHP_EOL;};$add->call($pandas, 5);// 输出 6

Callable 转为闭包(PHP7.1)

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

<?phpclass Foo{    protected $num = 1;    public static function hello(string $bar)    {        echo 'hello ' . $bar;    }}$hello = Closure::fromCallable(['Foo', 'hello']);$hello('world');

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

以上就是“PHP闭包及Clourse类的作用是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯