专栏首页Web技术布道师PHP 闭包及Closure类

PHP 闭包及Closure类

匿名函数

实现一个简单的匿名函数:

$func = function() {

    echo "this is a func\n";

};

上面就是一个简单的匿名函数,定义一个函数体,将函数体赋值给一个变量(php5.3之后支持该写法)。

实现闭包

1、当做参数传递:

<?php

// 定义一个匿名函数,赋值给$func

$func = function($param) {

    var_dump($param);

};

// 将匿名函数作为参数传入,并调用该参数

function dFunc($func, $param) {

    $func($param);

}

dFunc($func, '123'); // 输出:string(3) "123"

2、将匿名函数返回:

<?php

// 定义一个函数,在该函数中将内部的匿名函数返回

function cFunc($param) {

    $func = function($param1) use ($param) {

    echo "params:".$param1." ".$param;

};

return $func;

}

// 获取并调用匿名函数

$rCFunc = cFunc("123");

$rCFunc("456"); // params:456 123

捕获外界变量

闭包: 闭包是词法作用于的体现,一个持有外部环境自由变量的函数就是闭包。闭包体现的是在程序运行过程中,由 “不确定”变为“ 确定” 的过程。

捕获外部变量:在PHP中对捕获这一动作有了更清晰的表现,使用use关键字。如上面例2。

在上面的例2中,匿名函数$func通过use关键字捕获了外部的自由变量$param,在调用时通过传入cFunc()函数的参数123($param此时会变为“确定”状态),进而调用匿名函数时输出“params:456 123”。

use引入的是自由变量的副本。

例如:

<?php

/*

输出结果:

匿名函数执行前:p1:p1

匿名函数内修改后:p1:p2

匿名函数执行完:p1:p1

*/

function f1() {

    $p1 = "p1";

    echo "匿名函数执行前:p1:$p1\n";

    $func = function() use ($p1) {

        $p1 = "p2";

        echo "匿名函数内修改后:p1:$p1\n";

    };

$func();

echo "匿名函数执行完:p1:$p1\n";

}

f1();

golang闭包: 在golang中同样通过匿名函数实现了闭包,和PHP不同的是,golang中的闭包是默认会引入上下文的自由变量,且引入的地址,即在闭包函数内部修改变量会在函数外部生效。

PHP Closure类

用于代表匿名函数类。在PHP中定义一个闭包函数其实就是一个Closure类的实例。

<?php

/*

输出:

object(Closure)#1 (0) {

}

*/

$func = function() {};

    var_dump($func);

类摘要

Closure {

/* 方法 */

__construct ( void )

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

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

}
  • Closure::__construct — 用于禁止实例化的构造函数
  • Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。
  • Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。

Closure::bind

复制一个闭包,绑定指定的$this对象和类作用域,返回一个新的匿名函数

参数说明:

  • closure: 需要绑定的匿名函数。
  • newthis: 需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包。( 理解:可以选择是否将匿名函数绑定到一个类对象,若绑定到了一个类对象,则可以在匿名函数内使用 $this ,否则不可使用。 )
  • newscope: 想要绑定给闭包的类作用域,或者 'static' 表示不改变。如果传入一个对象,则使用这个对象的类型名。类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性。( 理解:如果传入一个类,则可以访问类的static、private、protected属性,否则只能访问public属性。 )

简单理解:可以简单理解为将该匿名函数绑定到一个类或实例。根据参数的不同,可以访问不同的类的属性。

<?php

class A{

    private static $_cat = 'cat';

    private $_dog = 'dog';

    public $pig = 'pig';

}

$cat = static function() {

    var_dump(A::$_cat);

};

$dog = function() {

    var_dump($this->_dog);

};

$pig = function() {

    var_dump($this->pig);

};

// 传入null,不可使用$this,但传入A类,则可以访问static等

$bindCat = Closure::bind($cat, null, 'A');

echo "bind cat\n";

$bindCat();

// 传入new A()对象,A类,可以使用$this访问私有属性。

$bindDog = Closure::bind($dog, new A(), 'A');

echo "bind dog\n";

$bindDog();

// 为传入类对象,不可使用$this

$bindDog2 = Closure::bind($dog, null, 'A');

echo "bind dog2\n";

$bindDog2();

输出:

bind cat

string(3) "cat"

bind dog

string(3) "dog"

bind dog2

Fatal error: Using $this when not in object context

Closure::bindTo

Closure::bind()的非静态形式。

小结

  • PHP通过匿名函数实现闭包。
  • 可以通过将匿名函数作为参数或返回值实现闭包。
  • 可以通过use关键字引入外部变量,且引入的变量副本。
  • 匿名函数均实现了Closure类,且可以通过Closure::bind()方法将匿名函数绑定到某个类。

本文分享自微信公众号 - PHP技术大全(phpgod)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++实现 STL 标准库和算法(一)实验楼笔记

    想 掌握C++强大标准库 通过本次课程,你将学习到 c++ template ,异常处理 ,并回顾数据库的部分知识 ,初步掌握 STL 开发 ,避免重复制造轮子...

    韩旭051
  • C++ 实现 STL 标准库和算法(二)template 编程和迭代器粗解 实验楼笔记

    本节内容主要讲述 c++11 模板的用法,以后的代码中会大量的用到模板的知识。同时简单讲解迭代器的相关知识,为后面容器和算法的内容作铺垫。

    韩旭051
  • CSS 基础系列:从清除浮动和margin塌陷问题谈BFC

    浮动的元素会影响其兄弟元素的位置,并可能导致父元素的高度塌陷(假如父元素没设置高度),因此需要清除浮动(带来的影响)。

    Chor
  • CSS 基础系列:inline-blcok和float

    简单比对一下div+css布局中的inline-block和float的特点,同时附上使用inline-block之后元素之间产生空隙的解决方法。 虽然设置浮...

    Chor
  • VS环境下C++万能头文件报错的解决方法

    今天我想要在C++中嵌入汇编语言来进行混合编程,发现一个小问题:VS或者VC++好像都不支持我最爱的C++万能头文件<bits/stdc++.h>,编译器会报错...

    喜欢ctrl的cxk
  • C++嵌入汇编语言计算有符号数组的平均值

    嵌入汇编是指在C和C++的源程序中插入汇编语言指令,也称内嵌汇编、内联汇编或行内汇编。VisualC++中使用“__asm”关键字指示嵌入汇编,不需要独立的汇编...

    喜欢ctrl的cxk
  • c++11/14快速入门(一)实验楼学习笔记

    从现在开始,你的脑子里应该树立 『C++ 不是 C 的一个超集』这个观念(而且从一开始就不是)。在编写 C++ 时,也应该尽可能的避免使用诸如 void* 之类...

    韩旭051
  • 「译」前端项目中常见的 CSS 问题

    快速摘要:近年来,跨浏览器的渲染和交互已经愈加一致。不过,它仍然没有达到完全一致,有很多小问题会让你出错。除了这些问题之外,还有不同的屏幕尺寸、语言偏好和明显的...

    Chor
  • 删除字符串中的子串(C++ regex求解)

    输入2个字符串S1和S2,要求删除字符串S1中出现的所有子串S2,即结果字符串中不能包含S2。

    喜欢ctrl的cxk
  • Python 核心设计理念27个问题及解答

    Guido van Rossum 认为使用缩进进行分组非常优雅,并且大大提高了普通 Python 程序的清晰度。大多数人在一段时间后就学会并喜欢上这个功能。

    小草AI

扫码关注云+社区

领取腾讯云代金券