Object not being destroyed until end of the script if it registers spl_autoload_register();

不问归期 提交于 2019-12-11 04:29:54

问题


Object not being destroyed before script ends can someone explain why using spl_autoload_register() prevents object from destruction when unset().

The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.

Does spl_autoload_register() have reference to the object that registered it or what happens?

class MyAutoLoader {

    public function registerAutoLoader() {

        spl_autoload_register(function ($class) {

        });

    }

    public function __destruct() {
        echo 'Destroying: ' . get_class($this) . "<br/>";
    }

}

$MyAutoLoader = new MyAutoLoader();

$MyAutoLoader->registerAutoLoader();

unset($MyAutoLoader);

echo 'End of script<br/>';

//End of script
//Destroying: MyAutoLoader

回答1:


Does spl_autoload_register() have reference to the object that registered it or what happens?

Yes, it does. But, doesn't because spl_autoload_register was called inside the class. That's happening because of your Closure.

As you can read in manual:

As of PHP 5.4.0, when declared in the context of a class, the current class is automatically bound to it, making $this available inside of the function's scope. If this automatic binding of the current class is not wanted, then static anonymous functions may be used instead.

When the closure has been created inside the class, it'll bound automatically the pseudo-variable $this. Then your instance will have two references:

  • $MyAutoLoader variable;
  • Closure passed to spl_autoload_register.

I've rewritten your example with a few differences which you can see the behavior:

class MyAutoLoader {

    private $instance = "Outside";

    public function registerAutoLoader(Closure $closure = null) {

        //If a closure ins't passed as parameter, a new one will be created
        if (!$closure instanceof Closure)
        {
            $this->instance = "Inside";
            //A closure created inside a class will bound the pseudo-variable $this
            $closure = function ($class) {};
        }

        spl_autoload_register($closure);

    }

    public function __destruct() {
        printf('Destroying: %s - %s instance<br/>' , get_class($this) , $this->instance);
    }

}

$MyAutoLoader = new MyAutoLoader();
$MyAutoLoader->registerAutoLoader();

$MyAutoLoader2 = new MyAutoLoader();

//A closure created outside of a class doesn't have the class scope
$MyAutoLoader2->registerAutoLoader(function($class){});

unset($MyAutoLoader , $MyAutoLoader2);

echo 'End of script<br/>';

And the result will be:

Destroying: MyAutoLoader - Outside the instance
End of script
Destroying: MyAutoLoader - Inside the instance

In the last example, the Closure has been created out of the class scope. So only the variable $MyAutoLoader2 has the instance of the class.

Another possible example can be:

class MyAutoLoader {

    public function registerAutoLoader(Closure $closure) {

        //Binding the class scope to the closure
        $closure = $closure->bindTo($this);

        spl_autoload_register($closure);

    }

    public function __destruct() {
        printf('Destroying: %s <br/>' , get_class($this));
    }

}

$MyAutoLoader = new MyAutoLoader();
$MyAutoLoader->registerAutoLoader(function($class){});
unset($MyAutoLoader);

echo 'End of script<br/>';

In this last example, I'm creating the Closure outside of class, but I'm binding the class scope into the class, creating a new reference to MyAutoLoader class. The result will be:

End of script
Destroying: MyAutoLoader 

A few more tips from bind and bindTo you can read at the link below:

How can I invoke a ReflectionFunction wrapping a closure that utilizes $this?



来源:https://stackoverflow.com/questions/40348781/object-not-being-destroyed-until-end-of-the-script-if-it-registers-spl-autoload

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!