1. 程式人生 > >php Closure $this作用域問題

php Closure $this作用域問題

今天遇到的個問題,

  1. 場景 class A 內部 定義了一個static function f1,
  2. 該static func  f1中例項了另一個class B
  3. f1然後使用B的例項進行setAttribute 操作,其中一個attribute值是一個匿名函式 cf1
  4. 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();