php 中的闭包函数详解

面向对象变成语言代码的复用主要采用继承来实现,而函数的复用,就是通过闭包来实现。这就是闭包的设计初衷。

 

注:PHP里面闭包函数是为了复用函数而设计的语言特性,如果在闭包函数里面访问指定域的变量,使用use关键字来实现。

 

PHP具有面向函数的编程特性,但是也是面向对象编程语言,PHP 会自动把闭包函数转换成内置类 Closure 的对象实例,依赖Closure 的对象实例又给闭包函数添加了更多的能力。 

 

闭包不能被实例(私有构造函数),也不能被继承(finally 类)。可以通过反射来判断闭包实例是否能被实例,继承。

 

匿名函数


提到闭包就不得不想起匿名函数,也叫闭包函数(closures),貌似PHP闭包实现主要就是靠它。声明一个匿名函数是这样:

 

1

2

3

$func function() {

 

}; //带结束符

  

可以看到,匿名函数因为没有名字,如果要使用它,需要将其返回给一个变量。匿名函数也像普通函数一样可以声明参数,调用方法也相同:

1

2

3

4

5

6

7

$func function$param ) {

    echo $param;

};

$func'some string' );

 

//输出:

//some string

  

顺便提一下,PHP在引入闭包之前,也有一个可以创建匿名函数的函数:create function,但是代码逻辑只能写成字符串,这样看起来很晦涩并且不好维护,所以很少有人用。

 

实现闭包


将匿名函数在普通函数中当做参数传入,也可以被返回。这就实现了一个简单的闭包。

 

连接闭包和外界变量的关键字:USE


PHP在默认情况下,匿名函数不能调用所在代码块的上下文变量,而需要通过使用use关键字。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

function getMoney() {

    $rmb = 1;

    $func function() use $rmb ) {

        echo $rmb;

        //把$rmb的值加1

        $rmb++;

    };

    $func();

    echo $rmb//闭包内的变量改变了,但是闭包外没有改变。

}

getMoney();

 

//输出:

//1

//1

  

注:use所引用的是变量的复制(副本而),并不是完全引用变量。如果要达到引用的效果,就需要使用 & 符号,进行引用传递参数。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

function getMoney() {

    $rmb = 1;

    $func function() use ( &$rmb ) {

        echo $rmb;

        //把$rmb的值加1

        $rmb++;

    };

    $func();

    echo $rmb;

}

getMoney();

 

//输出:

//1

//2

  

 


 

总结:

 

闭包函数不能直接访问闭包外的变量,而是通过use 关键字来调用上下文变量(闭包外的变量),也就是说通过use来引用上下文的变量;

闭包内所引用的变量不能被外部所访问(即,内部对变量的修改,外部不受影响),若想要在闭包内对变量的改变从而影响到上下文变量的值,需要使用&的引用传参。

 

 


 

 

PHP Closure 类是用于代表匿名函数的类,匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象,Closure类摘要如下:

1

2

3

4

5

Closure {

    __construct ( void )

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

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

}

  

方法说明:

1

2

3

Closure::__construct — 用于禁止实例化的构造函数

Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。

Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。

  

除了此处列出的方法,还有一个 __invoke 方法。这是为了与其他实现了 __invoke()魔术方法 的对象保持一致性,但调用闭包对象的过程与它无关。

 

参数说明:

closure表示需要绑定的闭包对象。
newthis表示需要绑定到闭包对象的对象,或者NULL创建未绑定的闭包。
newscope表示想要绑定给闭包的类作用域,可以传入类名或类的示例,默认值是 'static', 表示不改变。

 

返回值:成功时返回一个新的 Closure 对象,失败时返回FALSE。

 

Closure::bind是Closure::bindTo的静态版本

 

例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

class Animal {

    public $cat 'cat';

    public static $dog 'dog';

    private $pig 'pig';

    private static $duck 'duck';

}

 

//不能通过 $this 访问静态变量

//不同通过 类名::私有静态变量,只能通过self,或者static,在类里面访问私有静态变量

 

$cat function() {

    return $this->cat;

};

 

$dog static function () {

    return Animal::$dog;

};

 

$pig =  function() {

    return $this->pig;

};

 

$duck static function() {

    //return Animal::$duck;  这样写,会报错,提示不能通过类名访问私有静态变量

  return self::$duck// return static::$duck

};

 

$bindCat = Closure::bind($catnew Animal(), 'Animal');

$bindCat2 = Closure::bind($catnew Animal(), new Animal());

echo $bindCat() . PHP_EOL;

echo $bindCat2() . PHP_EOL;

 

$bindDog = Closure::bind($dog, null, 'Animal');

$bindDog2 = Closure::bind($dog, null, new Animal());

echo $bindDog() . PHP_EOL;

echo $bindDog2() . PHP_EOL;

 

$bindPig = Closure::bind($pignew Animal(), 'Animal');

$bindPig2 = Closure::bind($pignew Animal(), new Animal());

echo $bindPig() . PHP_EOL;

echo $bindPig2() . PHP_EOL;

 

$bindDuck = Closure::bind($duck, null, 'Animal');

$bindDuck2 = Closure::bind($duck, null, new Animal());

echo $bindDuck() . PHP_EOL;

echo $bindDuck2() . PHP_EOL;

 

通过上面的例子,可以看出函数复用得,可以把函数挂在不同的类上,或者对象上

 

总结:

1. 闭包内如果用 $this, 则 $this 只能调用非静态的属性,这和实际类中调用原则是一致的,且 Closure::bind() 方法的第2个参数不能为null,必须是一个实例 (因为$this,必须在实例中使用),第三个参数可以是实例,可以是类字符串,或 static;

2. 闭包内调用静态属性时,闭包必须声明为 static,同时Closure::bind()方法的第2个参数需要为null,因为 静态属性不需要实例,第3个参数可以是类字符串,实例,staic.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值