今天遇到的个问题,
- 场景 class A 内部 定义了一个static function f1,
- 该static func f1中实例了另一个class B
- f1然后使用B的实例进行setAttribute 操作,其中一个attribute值是一个匿名函数 cf1
- cf1依赖一个参数,该参数是 B 的实例
<?php
class A
{
public static function testClosureScope()
{
$objB = (new B)->setAttr1(
function (){
self::otherFunc();//todo 此处需要使用当前实例化的B对象作为参数
}
);
}
public static function otherFunc(B $objB)
{
var_dump($objB);
}
}
class B
{
public $attr1;
/**
* @return mixed
*/
public function getAttr1()
{
return $this->attr1;
}
/**
* @param mixed $attr1
*/
public function setAttr1($attr1)
{
$this->attr1 = $attr1;
return $this;
}
}
问题所在 :上面todo 的地方需要完善,How?
1.传递 $this
<?php
class A
{
public static function testClosureScope()
{
$objB = (new B)->setAttr1(
function (){
self::otherFunc($this);//todo 此处需要使用当前实例化的B对象作为参数
}
);
}
public static function otherFunc(B $objB)
{
var_dump($objB);
}
}
ERROR, 想法是好的,但是这个$this,是传递不过去的,原因:
-
当前 testClosureScope 方法是static
-
即使所在方法不是static,$this 也会自动绑定到 Class A的实例,即 Closure中 的 $this会自动bind到定义的类,不一定是调用的类
#################################################################################################
解决法
1.Closure的继承作用域变量
<?php
class A
{
public static function testClosureScope()
{
$objB = (new B);
$objB->setAttr1(
function ()use($objB){
self::otherFunc($objB);//todo 此处需要使用当前实例化的B对象作为参数
}
);
return $objB;
}
public static function otherFunc(B $objB)
{
var_dump($objB);
}
}
class B
{
public $attr1;
/**
* @return mixed
*/
public function getAttr1()
{
return $this->attr1;
}
/**
* @param mixed $attr1
*/
public function setAttr1($attr1)
{
$this->attr1 = $attr1;
return $this;
}
}
$obj = A::testClosureScope();
$cf = $obj->getAttr1();
$cf();//RECURSION 递归引用自己
2. Closure 的 bindTo
<?php
class A
{
public static function testClosureScope()
{
$f = function (){
self::otherFunc($this);//此处需要使用当前实例化的B对象作为参数
};
$objB = (new B);
$bindF = $f->bindTo($objB);//闭包绑定至 B实例;所以上面的 $this 才会生效;注意一定要接收返回值
$objB->setAttr1($bindF);
return $objB;
}
public static function otherFunc(B $objB)
{
var_dump($objB);
}
}
class B
{
public $attr1;
/**
* @return mixed
*/
public function getAttr1()
{
return $this->attr1;
}
/**
* @param mixed $attr1
*/
public function setAttr1($attr1)
{
$this->attr1 = $attr1;
return $this;
}
}
$obj = A::testClosureScope();
$cf = $obj->getAttr1();
$cf();