php Closure $this作用域問題
阿新 • • 發佈:2019-08-01
今天遇到的個問題,
- 場景 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();