php Closure $this scoping problem

Keywords: Programming PHP Attribute

Today's problems,

  1. Scenario class A defines a static function f1.
  2. Another class B is exemplified in this static func f1
  3. f1 then uses an instance of B for setAttribute operation, where one of the attribute s is an anonymous function cf1
  4. cf1 depends on a parameter, which is an example of B
<?php

class A
{
    public static function testClosureScope()
    {
        $objB = (new B)->setAttr1(
            function (){
                self::otherFunc();//todo Here you need to use the currently instantiated B object as a parameter
            }
        );
    }

    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;
    }


}

Question: The above todo needs to be improved, How?

1. Delivery of $this

<?php

class A
{
    public static function testClosureScope()
    {
        $objB = (new B)->setAttr1(
            function (){
                self::otherFunc($this);//todo Here you need to use the currently instantiated B object as a parameter
            }
        );
    }

    public static function otherFunc(B $objB)
    {
        var_dump($objB);
    }
}

ERROR, the idea is good, but this $this is not transferable, the reason is:

  • The current testClosureScope method is static

  • Even if the method is not static, $this will automatically bind to an instance of Class A, that is, $this in Closure will automatically bind to the class defined, not necessarily the class invoked.

#################################################################################################

Solution method

1.Closure's Inheritance Scope Variables

<?php

class A
{
    public static function testClosureScope()
    {
        $objB = (new B);

        $objB->setAttr1(
            function ()use($objB){
                self::otherFunc($objB);//todo Here you need to use the currently instantiated B object as a parameter
            }
        );

        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 recursively refers to itself

2. Closure's bindTo

<?php

class A
{
    public static function testClosureScope()
    {
        $f = function (){
                self::otherFunc($this);//Here you need to use the currently instantiated B object as a parameter
            };
        $objB = (new B);

        $bindF = $f->bindTo($objB);//Closure is bound to instance B; so the $this above will take effect; be careful to receive the return value
        $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();

Posted by bogins on Sat, 12 Oct 2019 11:02:25 -0700