php 匿名函数,PHP 匿名函数初探

966b5d3a46c88e16208d57b16ee5fd52.png

PHP中的闭包函数

Closure —-> 匿名函数,又称为 Anonymous functions , 是 PHP5.3 的时候引入的。

匿名函数 就是没有定义名字的函数。

非匿名函数

// 非匿名函数

function test()

{

return 100;

}

// 测试匿名函数的方法

// 传入的参数是一个匿名函数

function testClosure(Closure $callback)

{

return $callback();

}

$a = testClosure(test());

print_r($a);// 报错,因为传入的函数 test() 并非匿名函数 PHP Fatal error: Uncaught TypeError: Argument 1 passed to testClosure() must be an instance of Closure, integer given

上面的报错是指,函数 testClosure() 中传入的参数应该是一个 匿名函数 的实例,却传入一个 int 类型的值。

因为 test() 不是匿名函数,因此 test() 的出现相当于调用这个函数,也就是说 $a = testClosure(test()); 跟 $a = testClosure(10); 效果是等同的;

匿名函数

// 匿名函数

$f = function()

{

return 10;

};

// 测试匿名函数的方法

// 传入的参数是一个匿名函数

function testClosure(Closure $callback)

{

return $callback();

}

$a = testClosure($f);

print_r($a); // 10

调用一个类中的匿名函数

class C

{

public static function testC()

{

return function ($i) {

return $i + 10;

};

}

}

function testClosure(Closure $callback)

{

// 调用传入的闭包函数,并给闭包函数中传入参数13

return $callback(13);

}

$a = testClosure(C::testC());

print_r($a);

testClosure(C::testC()); 中的 C::testC() 就相当于 :

function ($i) {

return $i + 10;

};

C::testC() 返回的是一个 funciton。

绑定的概念

上面的例子的 Closure 只是 全局的的匿名函数,好了,我现在想指定一个类有一个匿名函数。

也可以理解说,这个匿名函数的访问范围不再是全局的了,是一个类的访问范围。

bind

(PHP 5 >= 5.4.0, PHP 7)

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

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

bind 一共三个参数:

需要绑定的匿名函数;

需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包;

想要绑定给闭包的类作用域,或者 ‘static’ 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性。

注意

Closure::bind() 在使用时,最少得有两个参数,如果第二个参数不是很有必要的话,可以写 null 填充

将一个 匿名函数 绑定到一个类中。

class A

{

public $base = 100;

}

class B

{

private $base = 1000;

}

$f = function()

{

return $this->base + 3;

};

$a = Closure::bind($f, new A);

print_r($a()); // 103

echo PHP_EOL;

$b = Closure::bind($f, new B , 'B');

print_r($b()); // 1003

echo PHP_EOL;

上面的代码中,f 这个匿名函数中莫名其妙出现了一个 $this, 就说明这个函数是需要绑定到类中使用的,也可以说是 匿名函数 中的 $this 指向某个类的实例对象上。

就像这样:

$f = function()

{

$this = new A() / new B(); // 只是类比,实际上不能这么用,因为 $this 是关键字

return $this->base + 3;

};

但是我们注意到,这里两个 bind 传入的参数个数是不同的,而且两个类 A 、B 中的 $base 变量作用域是不同的,前者是 public ,或者为 private。

public、protected、private

public :公有属性,在子类中可以通过 self::var调用 public方法或属性,parent::method 调用父类方法 。在实例中可以能**过 $obj->var 来调用 public 类型的方法或属性;

protected:受保护属性,在子类中可以通过 self::var 调用 protected 方法或属性,parent::method 调用父类方法,在实例中不能通过 $obj->var来调用 protected 类型的方法或属性;

private: 私有属性,该类型的属性或方法只能在该类中使用,在该类的实例、子类中、子类的实例中都不能调用私有类型的属性和方法。

因此,$b 相对于 $a 而言,在绑定时,多了第三个参数, 就是为了将 class B 的私有属性 转化为 公有属性 以便于在外部通过 $this->base 进行访问。

举个🌰

class A {

private $name = '王力宏';

protected $age = '30';

private static $weight = '70kg';

public $address = '中国';

public static $height = '180cm';

}

$fun = function() {

return $this->address;

};

$fun1 = function() {

return $this->name;

};

$fun2 = function() {

return A::height;

};

$fun3 = function() {

return A::weight;

};

将 fun、fun1、fun2、fun3 绑定到类 A 的情况咱们分别讨论:

$fun:

$a = Closure::bind($fun, new A());

print_r($a()); // 中国

因为访问的是类 A 的公有属性,且匿名函数中包含 $this 关键词,所以只需要前两个参数就可以。

$fun1:

$b = Closure::bind($fun1, new A(), 'A');

print_r($b()); // 王力宏

因为访问的是类 A 的私有属性,且匿名函数中包含 $this 关键词,所以三个参数都需要,将 私有属性 转化为 公有属性 访问。

$fun2:

$c = Closure::bind($fun2, null);

print_r($c()); // 180cm

// 或者

$c = Closure::bind($fun2, new A);

print_r($c());// 180cm

因为访问的是类 A 的公有静态属性,且匿名函数中包含 类名::静态属性 调用形式,其中已指明绑定的类名,因此第二个参数可写明或者用 null 填充。

fun3:

$d = Closure::bind($fun3, null, 'A');

print_r($d()); // 70kg

// 或者

$d = Closure::bind($fun3, new A, 'A');

print_r($d());// 70kg

因为访问的是类 A 的私有静态属性,且匿名函数中包含 类名::静态属性 调用形式,其中已指明绑定的类名,因此第二个参数可写明类名或者用 null 填充,且第三个参数必须有。

总结

一般匿名函数中有 $this->$name 类似这样用 $this 访问属性方式时,你在使用 bind 绑定时 ,第二个参数肯定要写,写出你绑定那个对象实例,第三个参数要不要呢,要看你访问的这个属性,在绑定对象中的权限属性,如果是 private,protected 你要使用第三个参数使其变为 公有属性, 如果本来就是公有,你可以省略,也可以不省略;

一般匿名函数中是 类名::静态属性 类似这样的访问方式(比如例子中 A::$weight),你在使用 bind 绑定时,第二个参数可以写 null,也可以写出具体的对象实例,一般写 null 就行(写了具体对象实例多此一举),第三个参数写不写还是得看你访问的这个静态属性的权限是 private 还是 public,如果不是public,第三个参数能使其权限变为公有属性正常访问,如果本来就是公有public可以不用写,可以省略。

bindTo

(PHP 5 >= 5.4.0, PHP 7)

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

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

创建并返回一个 匿名函数, 它与当前对象的函数体相同、绑定了同样变量,但可以绑定不同的对象,也可以绑定新的类作用域。

“绑定的对象”决定了函数体中的 $this 的取值,“类作用域”代表一个类型、决定在这个匿名函数中能够调用哪些 私有 和 保护 的方法。 也就是说,此时 $this 可以调用的方法,与 newscope 类的成员函数是相同的。

静态闭包不能有绑定的对象( newthis 参数的值应该设为 NULL)不过仍然可以用 bubdTo 方法来改变它们的类作用域。

参数

newthis

绑定给匿名函数的一个对象,或者 NULL 来取消绑定。

newscope

关联到匿名函数的类作用域,或者 static 保持当前状态。如果是一个对象,则使用这个对象的类型为新的类作用域。 这会决定绑定的对象的 保护、私有成员 方法的可见性。

使用

Closure::bindTo 是 Closure::bind的动态方法,Closure::bind 是 Closure::bindTo 的静态方法,差别在于 Closure::bindTo 共有两个参数,Closure::bind共有三个参数。

举个🌰

上面的四个小例子,换成 bindTo 应该是:

// fun

$a = $fun -> bindTo(new A());

print_r($a()); // 中国

// fun1

$b = $fun1 -> bindTo(new A(), 'A');

print_r($b()); // 王力宏

// fun2

$c = fun2 -> bindTo(null);

print_r($c()); // 180cm

// 或者

$c = Closure::bindTo(new A);

print_r($c());// 180cm

// fun3

$d = $fun3 -> bindTo(null, 'A');

print_r($d()); // 70kg

// 或者

$d = $fun3 -> bindTo(new A, 'A');

print_r($d());// 70kg

转载🔗

本作品采用《CC 协议》,转载必须注明作者和本文链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值